Download code/bugfind/bench/make_kernels.py from viai957/align: direct link, hf CLI and curl.
- Browser
- Download file 25.2 kB
-
https://huggingface.co/viai957/align/resolve/main/code/bugfind/bench/make_kernels.py
- Command line
-
hf download hf://viai957/align/code/bugfind/bench/make_kernels.py
-
curl -L -o make_kernels.py https://huggingface.co/viai957/align/resolve/main/code/bugfind/bench/make_kernels.py
25.2 kB
| #!/usr/bin/env python3 -I | |
| """Minimal-extraction items (Phase 5 Part A, "extract the affected pure function into a minimal standalone crate"). | |
| Each KERNEL is a hand-extracted, dependency-free reduction of the *decision logic* that a RustSec fix changed | |
| (pre = vulnerable revision's logic, post = patched revision's logic). Whole crates are not translatable (native deps, | |
| dyn traits, early returns in loops, ...: see TOOLCHAIN.md / SUMMARY.json), so the unit is the function kernel. | |
| `fidelity`: | |
| verbatim_logic the changed expression/branch is copied from the crate with std/crate types replaced by integers/slices | |
| model_of_std the vulnerable behaviour lives in a std/crate call (slice split_at, str slicing, unchecked memcpy length); | |
| the kernel models that call's panic/UB condition explicitly. Weaker; reported separately. | |
| Extraction was done by reading the pre/post diff, so kernels are NOT blind to the bug; only the *properties* (property bank) | |
| are authored blind, from `spec_doc` + signature alone (see baselines/bank/README_PROVENANCE.md). | |
| Writes bench/kernels/<id>/{meta.json,pre/{Cargo.toml,src/lib.rs},post/{Cargo.toml,src/lib.rs}}. | |
| """ | |
| import json, os | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| CAND = "/apps/development/rlhf/bugfind_data/out/advisory_candidates.jsonl" | |
| K = [] | |
| def k(kid, adv, fn, sig, spec_doc, bug_class, fidelity, pre, post, witness, note, file): | |
| K.append(dict(id=kid, adv=adv, fn=fn, sig=sig, spec_doc=spec_doc, bug_class=bug_class, fidelity=fidelity, | |
| pre=pre.strip() + "\n", post=post.strip() + "\n", witness=witness, note=note, file=file)) | |
| k("claxon_rice", "RUSTSEC-2018-0004", "rice_layout", "pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result<u32, u8>", | |
| "Computes how many residual samples a FLAC Rice-coded subframe's 2^order partitions cover (order is a 4-bit field, so order > 15 is rejected with Err). On Ok(n), n must equal block_size (the partitions fill the block); otherwise return Err.", | |
| "logic", "verbatim_logic", | |
| """ | |
| pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result<u32, u8> { | |
| if order > 15 { | |
| return Err(3); | |
| } | |
| let n_partitions = 1u32 << order; | |
| let n_samples_per_partition = block_size >> order; | |
| if n_warm_up > n_samples_per_partition { | |
| return Err(1); | |
| } | |
| Ok(n_partitions * (n_samples_per_partition as u32)) | |
| } | |
| """, """ | |
| pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result<u32, u8> { | |
| if order > 15 { | |
| return Err(3); | |
| } | |
| let n_partitions = 1u32 << order; | |
| let n_samples_per_partition = block_size >> order; | |
| if block_size & ((n_partitions - 1) as u16) != 0 { | |
| return Err(2); | |
| } | |
| if n_warm_up > n_samples_per_partition { | |
| return Err(1); | |
| } | |
| Ok(n_partitions * (n_samples_per_partition as u32)) | |
| } | |
| """, "10u16, 2u32, 0u16", "src/subframe.rs decode_residual: block size not a multiple of 2^order left buffer tail uninitialised", "src/subframe.rs") | |
| k("bytes_reserve", "RUSTSEC-2026-0007", "reserve_fits", "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool", | |
| "Decides whether a Vec-backed buffer with capacity v_capacity can serve a reserve request of new_cap bytes when the live window starts at offset; must be true iff v_capacity >= new_cap + offset in exact arithmetic.", | |
| "overflow", "verbatim_logic", | |
| "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool {\n v_capacity >= new_cap + offset\n}", | |
| """ | |
| pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool { | |
| match new_cap.checked_add(offset) { | |
| Some(s) => v_capacity >= s, | |
| None => false, | |
| } | |
| } | |
| """, "10usize, usize::MAX, 1usize", "src/bytes_mut.rs reserve_inner: new_cap + offset overflow", "src/bytes_mut.rs") | |
| k("mldsa_hint", "RUSTSEC-2026-0076", "hint_weight", "pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option<usize>", | |
| "Decodes the ML-DSA signature hint encoding: hint[..max_ones] are positions, hint[max_ones..max_ones+rows] are cumulative counts that must be non-decreasing and at most max_ones. Returns the sum of the hint bytes it consumed, or None for a malformed encoding. Must never panic on any input of length >= max_ones+rows.", | |
| "panic", "verbatim_logic", | |
| """ | |
| pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option<usize> { | |
| let mut previous = 0usize; | |
| let mut total = 0usize; | |
| let mut bad = false; | |
| let mut i = 0usize; | |
| while i < rows { | |
| let current = hint[max_ones + i] as usize; | |
| if current < previous || previous > max_ones { | |
| bad = true; | |
| } else { | |
| let mut j = previous; | |
| while j < current { | |
| total += hint[j] as usize; | |
| j += 1; | |
| } | |
| previous = current; | |
| } | |
| i += 1; | |
| } | |
| if bad { None } else { Some(total) } | |
| } | |
| """, """ | |
| pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option<usize> { | |
| let mut previous = 0usize; | |
| let mut total = 0usize; | |
| let mut bad = false; | |
| let mut i = 0usize; | |
| while i < rows { | |
| let current = hint[max_ones + i] as usize; | |
| if current < previous || current > max_ones { | |
| bad = true; | |
| } else { | |
| let mut j = previous; | |
| while j < current { | |
| total += hint[j] as usize; | |
| j += 1; | |
| } | |
| previous = current; | |
| } | |
| i += 1; | |
| } | |
| if bad { None } else { Some(total) } | |
| } | |
| """, "&[0u8, 0, 200], 2usize, 1usize", "src/ml_dsa_generic.rs / encoding/signature.rs deserialize hint: checked previous instead of current against max_ones", "src/encoding/signature.rs") | |
| k("mldsa_norm", "RUSTSEC-2026-0076", "response_bound", "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32", | |
| "ML-DSA verification bound for the signer response: gamma1 - beta where gamma1 = 2^gamma1_exponent.", | |
| "logic", "verbatim_logic", | |
| "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32 {\n (2i32 << gamma1_exponent) - beta\n}", | |
| "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32 {\n (1i32 << gamma1_exponent) - beta\n}", | |
| "17u32, 78i32", "src/ml_dsa_generic.rs verify: (2 << GAMMA1_EXPONENT) - BETA instead of (1 << ...) - BETA", "src/ml_dsa_generic.rs") | |
| k("odoh_split", "RUSTSEC-2023-0095", "encrypted_payload_len", "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result<usize, u8>", | |
| "Splits an encrypted ODoH query into an encapsulated key (first key_size bytes) and ciphertext (the rest); returns the ciphertext length, or Err if the message is shorter than key_size. Must not panic on any input.", | |
| "panic", "model_of_std", | |
| "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result<usize, u8> {\n let ct = &msg[key_size..];\n Ok(ct.len())\n}", | |
| "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result<usize, u8> {\n if key_size > msg.len() {\n return Err(1);\n }\n let ct = &msg[key_size..];\n Ok(ct.len())\n}", | |
| "&[1u8, 2, 3], 32usize", "src/protocol.rs decrypt_query: split_at(key_size) without length check", "src/protocol.rs") | |
| k("matrix_power", "RUSTSEC-2025-0065", "normalize_power_level", "pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64", | |
| "Scales a Matrix user power level (|power_level| < 2^53) to the range 0..=100 relative to max_power_level > 0.", | |
| "panic", "verbatim_logic", | |
| """ | |
| const INT_MAX: i64 = 9007199254740991; | |
| pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64 { | |
| let n = (power_level * 100) / max_power_level; | |
| assert!(n >= -INT_MAX && n <= INT_MAX); | |
| n | |
| } | |
| """, """ | |
| pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64 { | |
| let n = (power_level * 100) / max_power_level; | |
| if n < 0 { | |
| 0 | |
| } else if n > 100 { | |
| 100 | |
| } else { | |
| n | |
| } | |
| } | |
| """, "9007199254740991i64, 1i64", "src/room/members.rs normalized_power_level: expect() on out-of-range Int when max_power_level is small", "src/room/members.rs") | |
| k("nostr_iv", "RUSTSEC-2026-0219", "load_iv", "pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8>", | |
| "Loads a NIP-04 AES-CBC initialisation vector from untrusted bytes; must return Err unless the input is exactly 16 bytes, and must never panic.", | |
| "panic", "model_of_std", | |
| """ | |
| pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8> { | |
| let mut out = [0u8; 16]; | |
| let mut i = 0usize; | |
| while i < 16 { | |
| out[i] = iv[i]; | |
| i += 1; | |
| } | |
| Ok(out) | |
| } | |
| """, """ | |
| pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8> { | |
| if iv.len() != 16 { | |
| return Err(1); | |
| } | |
| let mut out = [0u8; 16]; | |
| let mut i = 0usize; | |
| while i < 16 { | |
| out[i] = iv[i]; | |
| i += 1; | |
| } | |
| Ok(out) | |
| } | |
| """, "&[1u8, 2, 3]", "src/nips/nip04.rs decrypt: iv.as_slice().into() panics on wrong length", "src/nips/nip04.rs") | |
| k("phone_ctx", "RUSTSEC-2023-0082", "context_prefix_skip", "pub fn context_prefix_skip(s: &[u8]) -> usize", | |
| "Returns how many leading bytes of an RFC3966 phone-context value to skip: 1 if it starts with '+', otherwise 0. Must not panic on empty input.", | |
| "panic", "verbatim_logic", | |
| "pub fn context_prefix_skip(s: &[u8]) -> usize {\n if s[0] == b'+' { 1 } else { 0 }\n}", | |
| "pub fn context_prefix_skip(s: &[u8]) -> usize {\n if !s.is_empty() && s[0] == b'+' { 1 } else { 0 }\n}", | |
| "&[]", "src/parser/rfc3966.rs: s.as_bytes()[0] on empty phone-context", "src/parser/rfc3966.rs") | |
| k("poly1305_key", "RUSTSEC-2026-0073", "key_len_ok", "pub fn key_len_ok(key: &[u8]) -> bool", | |
| "Poly1305 one-time keys are r (16 bytes) followed by s (16 bytes): a key is acceptable iff it is exactly 32 bytes.", | |
| "logic", "verbatim_logic", | |
| "pub const KEY_LEN: usize = 16;\npub fn key_len_ok(key: &[u8]) -> bool {\n key.len() == KEY_LEN\n}", | |
| "pub const KEY_LEN: usize = 32;\npub fn key_len_ok(key: &[u8]) -> bool {\n key.len() == KEY_LEN\n}", | |
| "&[0u8; 32]", "src/lib.rs KEY_LEN = 16 (standalone mac rejected/panicked on real 32-byte keys)", "src/lib.rs") | |
| k("ecdh_scalar", "RUSTSEC-2026-0023", "validate_x25519_scalar", "pub fn validate_x25519_scalar(s: &[u8]) -> bool", | |
| "Validates an X25519 secret scalar: must be exactly 32 bytes, not all zero, and clamped (low 3 bits of byte 0 clear, top bit of byte 31 clear, second-highest bit of byte 31 set).", | |
| "logic", "verbatim_logic", | |
| """ | |
| pub fn validate_x25519_scalar(s: &[u8]) -> bool { | |
| let mut all_zero = true; | |
| let mut i = 0usize; | |
| while i < s.len() { | |
| if s[i] != 0 { | |
| all_zero = false; | |
| } | |
| i += 1; | |
| } | |
| !all_zero | |
| } | |
| """, """ | |
| pub fn validate_x25519_scalar(s: &[u8]) -> bool { | |
| if s.len() != 32 { | |
| return false; | |
| } | |
| let mut all_zero = true; | |
| let mut i = 0usize; | |
| while i < s.len() { | |
| if s[i] != 0 { | |
| all_zero = false; | |
| } | |
| i += 1; | |
| } | |
| if all_zero { | |
| return false; | |
| } | |
| (s[0] & 7) == 0 && (s[31] & 128) == 0 && (s[31] & 64) != 0 | |
| } | |
| """, "&[1u8, 2, 3]", "src/ecdh.rs validate_scalar: only checked all-zero", "src/ecdh.rs") | |
| k("nanoid_mask", "RUSTSEC-2024-0343", "alphabet_mask", "pub fn alphabet_mask(len: usize) -> usize", | |
| "Bit mask used to index an alphabet of len symbols (len >= 2) from a random byte: the smallest all-ones value m with m >= len - 1, i.e. next_power_of_two(len) - 1.", | |
| "logic", "verbatim_logic", | |
| "pub fn alphabet_mask(len: usize) -> usize {\n len - 1\n}", | |
| """ | |
| pub fn alphabet_mask(len: usize) -> usize { | |
| let mut p = 1usize; | |
| while p < len { | |
| p = p * 2; | |
| } | |
| p - 1 | |
| } | |
| """, "62usize", "src/lib.rs MASK = $len - 1 is not a bit mask for non-power-of-two alphabets (biased/short alphabet)", "src/lib.rs") | |
| k("tar_pax", "RUSTSEC-2026-0145", "apply_pax", "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool", | |
| "PAX extended-header data describes the next file entry. Returns whether pending PAX data must be applied to a header of the given type byte: only for real entries, never for GNU long-name 'L', long-link 'K', PAX local 'x' or global 'g' headers.", | |
| "logic", "verbatim_logic", | |
| "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool {\n has_pax\n}", | |
| """ | |
| pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool { | |
| let mut is_extension_header = false; | |
| if entry_type == b'L' || entry_type == b'K' || entry_type == b'x' || entry_type == b'g' { | |
| is_extension_header = true; | |
| } | |
| if has_pax { | |
| if is_extension_header { false } else { true } | |
| } else { | |
| false | |
| } | |
| } | |
| """, "b'L', true", "src/archive.rs: PAX data applied to extension headers (desynchronisation)", "src/archive.rs") | |
| k("exif_discard", "RUSTSEC-2021-0143", "discard_exact", "pub fn discard_exact(avail: usize, len: usize) -> Result<usize, u8>", | |
| "Models skipping len bytes of a reader that has only avail bytes: returns Ok(number of read rounds) when the reader had enough data, Err when it hits EOF early. Must terminate on every input.", | |
| "dos_loop_or_recursion", "verbatim_logic", | |
| """ | |
| pub fn discard_exact(avail: usize, len: usize) -> Result<usize, u8> { | |
| let mut avail = avail; | |
| let mut len = len; | |
| let mut rounds = 0usize; | |
| while len > 0 { | |
| let consume_len = if avail < len { avail } else { len }; | |
| avail -= consume_len; | |
| len -= consume_len; | |
| rounds += 1; | |
| } | |
| Ok(rounds) | |
| } | |
| """, """ | |
| pub fn discard_exact(avail: usize, len: usize) -> Result<usize, u8> { | |
| let mut avail = avail; | |
| let mut len = len; | |
| let mut rounds = 0usize; | |
| let mut eof = false; | |
| while len > 0 && !eof { | |
| let consume_len = if avail < len { avail } else { len }; | |
| if consume_len == 0 { | |
| eof = true; | |
| } else { | |
| avail -= consume_len; | |
| len -= consume_len; | |
| rounds += 1; | |
| } | |
| } | |
| if eof { Err(1) } else { Ok(rounds) } | |
| } | |
| """, "3usize, 10usize", "src/util.rs discard_exact: spins forever at EOF (consume_len == 0)", "src/util.rs") | |
| k("trustdns_ptr", "RUSTSEC-2018-0007", "pointer_ok", "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool", | |
| "A DNS name-compression pointer is acceptable iff its target lies strictly before the start of the name currently being parsed (so pointer chains cannot loop).", | |
| "dos_loop_or_recursion", "verbatim_logic", | |
| "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool {\n let _ = name_start;\n location < pointer_location\n}", | |
| "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool {\n let _ = pointer_location;\n location < name_start\n}", | |
| "0usize, 2usize, 0usize", "src/rr/domain/name.rs Name::read: pointer compared with current label instead of name start (self-referential name)", "src/rr/domain/name.rs") | |
| k("ring_ctr", "RUSTSEC-2025-0009", "increment_by", "pub fn increment_by(old_value: u32, increment_by: u32) -> u32", | |
| "Increments a 32-bit big-endian AES-GCM block counter, wrapping modulo 2^32.", | |
| "overflow", "verbatim_logic", | |
| "pub fn increment_by(old_value: u32, increment_by: u32) -> u32 {\n old_value + increment_by\n}", | |
| "pub fn increment_by(old_value: u32, increment_by: u32) -> u32 {\n old_value.wrapping_add(increment_by)\n}", | |
| "4294967295u32, 1u32", "src/aead/aes.rs increment_by_less_safe: + panics with overflow checks", "src/aead/aes.rs") | |
| k("stack_insert", "RUSTSEC-2020-0042", "insert_shift_len", "pub fn insert_shift_len(len: usize, index: usize) -> Result<usize, u8>", | |
| "Number of elements to shift when inserting at index into a vector of length len; Err if index > len.", | |
| "panic", "model_of_std", | |
| "pub fn insert_shift_len(len: usize, index: usize) -> Result<usize, u8> {\n Ok(len.wrapping_sub(index))\n}", | |
| "pub fn insert_shift_len(len: usize, index: usize) -> Result<usize, u8> {\n if index > len {\n return Err(1);\n }\n Ok(len - index)\n}", | |
| "3usize, 5usize", "src/vector.rs insert: missing index <= len assert; copy length len - index wrapped (release) -> OOB write", "src/vector.rs") | |
| k("tract_len", "RUSTSEC-2026-0217", "tensor_len_ok", "pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool", | |
| "NNEF tensor header consistency: true iff prod(dims) * (bits_per_item / 8) == data_size_bytes in exact arithmetic (false if the product does not fit usize).", | |
| "overflow", "verbatim_logic", | |
| """ | |
| pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool { | |
| let mut len = 1usize; | |
| let mut i = 0usize; | |
| while i < dims.len() { | |
| len = len * dims[i]; | |
| i += 1; | |
| } | |
| len * (bits_per_item / 8) == data_size_bytes | |
| } | |
| """, """ | |
| pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool { | |
| let mut len = 1usize; | |
| let mut overflow = false; | |
| let mut i = 0usize; | |
| while i < dims.len() { | |
| let d = dims[i]; | |
| if d != 0 && len > usize::MAX / d { | |
| overflow = true; | |
| } else { | |
| len = len * d; | |
| } | |
| i += 1; | |
| } | |
| if overflow { | |
| return false; | |
| } | |
| let per = bits_per_item / 8; | |
| if per != 0 && len > usize::MAX / per { | |
| return false; | |
| } | |
| len * per == data_size_bytes | |
| } | |
| """, "&[4294967296usize, 4294967296], 8usize, 0usize", "src/tensors.rs read_tensor: unchecked shape product", "src/tensors.rs") | |
| k("transpose_dims", "RUSTSEC-2023-0080", "dims_match", "pub fn dims_match(width: usize, height: usize, len: usize) -> bool", | |
| "True iff width * height == len in exact arithmetic (false when the product does not fit usize).", | |
| "overflow", "verbatim_logic", | |
| "pub fn dims_match(width: usize, height: usize, len: usize) -> bool {\n width * height == len\n}", | |
| "pub fn dims_match(width: usize, height: usize, len: usize) -> bool {\n match width.checked_mul(height) {\n Some(p) => p == len,\n None => false,\n }\n}", | |
| "4294967296usize, 4294967296usize, 0usize", "src/lib.rs transpose: assert_eq!(w*h, len) wraps in release -> buffer overflow", "src/lib.rs") | |
| k("toodee_drain", "RUSTSEC-2025-0062", "drain_col_copy_len", "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize", | |
| "When removing column col from a row of orig_cols cells, the number of cells to shift left: those strictly after col (orig_cols - col - 1).", | |
| "overflow", "verbatim_logic", | |
| "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize {\n orig_cols - col\n}", | |
| "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize {\n orig_cols - col - 1\n}", | |
| "5usize, 2usize", "src/toodee.rs DrainCol::drop: ptr::copy length off by one (heap overflow)", "src/toodee.rs") | |
| k("tinyhttp_hdr", "RUSTSEC-2020-0031", "header_field_ok", "pub fn header_field_ok(s: &[u8]) -> bool", | |
| "A header field name is valid iff it is ASCII and contains no whitespace (no trimming: ' Transfer-Encoding' and 'Transfer-Encoding ' are invalid).", | |
| "logic", "verbatim_logic", | |
| """ | |
| fn is_ws(b: u8) -> bool { | |
| b == b' ' || b == b'\\t' || b == b'\\n' || b == b'\\r' || b == 11u8 || b == 12u8 | |
| } | |
| pub fn header_field_ok(s: &[u8]) -> bool { | |
| let mut start = 0usize; | |
| let mut end = s.len(); | |
| while start < end && is_ws(s[start]) { | |
| start += 1; | |
| } | |
| while end > start && is_ws(s[end - 1]) { | |
| end -= 1; | |
| } | |
| let mut ok = true; | |
| let mut i = start; | |
| while i < end { | |
| if s[i] >= 128 { | |
| ok = false; | |
| } | |
| i += 1; | |
| } | |
| ok | |
| } | |
| """, """ | |
| fn is_ws(b: u8) -> bool { | |
| b == b' ' || b == b'\\t' || b == b'\\n' || b == b'\\r' || b == 11u8 || b == 12u8 | |
| } | |
| pub fn header_field_ok(s: &[u8]) -> bool { | |
| let mut ok = true; | |
| let mut i = 0usize; | |
| while i < s.len() { | |
| if s[i] >= 128 || is_ws(s[i]) { | |
| ok = false; | |
| } | |
| i += 1; | |
| } | |
| ok | |
| } | |
| """, "b\"Transfer-Encoding \"", "src/common.rs HeaderField::from_str: trimmed whitespace (request smuggling)", "src/common.rs") | |
| k("evm_memset", "RUSTSEC-2021-0066", "memory_set_len", "pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option<usize>, limit: usize) -> Result<usize, u8>", | |
| "New length of EVM memory after writing value (value_len bytes) at offset, zero-padded to target_size (default value_len). Err if offset+target_size exceeds limit. Writing an empty value must not grow memory.", | |
| "dos_loop_or_recursion", "verbatim_logic", | |
| """ | |
| pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option<usize>, limit: usize) -> Result<usize, u8> { | |
| let target = match target_size { | |
| Some(t) => t, | |
| None => value_len, | |
| }; | |
| match offset.checked_add(target) { | |
| Some(pos) => { | |
| if pos > limit { | |
| return Err(1); | |
| } | |
| } | |
| None => return Err(1), | |
| } | |
| if cur_len < offset + target { | |
| Ok(offset + target) | |
| } else { | |
| Ok(cur_len) | |
| } | |
| } | |
| """, """ | |
| pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option<usize>, limit: usize) -> Result<usize, u8> { | |
| if value_len == 0 { | |
| return Ok(cur_len); | |
| } | |
| let target = match target_size { | |
| Some(t) => t, | |
| None => value_len, | |
| }; | |
| match offset.checked_add(target) { | |
| Some(pos) => { | |
| if pos > limit { | |
| return Err(1); | |
| } | |
| } | |
| None => return Err(1), | |
| } | |
| if cur_len < offset + target { | |
| Ok(offset + target) | |
| } else { | |
| Ok(cur_len) | |
| } | |
| } | |
| """, "0usize, 0usize, 0usize, Some(1000usize), 1048576usize", "src/memory.rs Memory::set: empty value with large target_size over-allocates", "src/memory.rs") | |
| k("bcrypt_split", "RUSTSEC-2026-0199", "split_hash_salt_len", "pub fn split_hash_salt_len(hash: &[u8]) -> Result<usize, u8>", | |
| "Validates a bcrypt hash string and returns the salt length (22). A valid hash is exactly 60 ASCII bytes; every other input must give Err, never panic.", | |
| "panic", "model_of_std", | |
| """ | |
| fn is_char_boundary(b: u8) -> bool { | |
| b < 128 || b >= 192 | |
| } | |
| pub fn split_hash_salt_len(hash: &[u8]) -> Result<usize, u8> { | |
| if hash.len() != 60 { | |
| return Err(1); | |
| } | |
| assert!(is_char_boundary(hash[22])); | |
| Ok(22) | |
| } | |
| """, """ | |
| pub fn split_hash_salt_len(hash: &[u8]) -> Result<usize, u8> { | |
| if hash.len() != 60 { | |
| return Err(1); | |
| } | |
| let mut ascii = true; | |
| let mut i = 0usize; | |
| while i < hash.len() { | |
| if hash[i] >= 128 { | |
| ascii = false; | |
| } | |
| i += 1; | |
| } | |
| if !ascii { | |
| return Err(2); | |
| } | |
| Ok(22) | |
| } | |
| """, "&[b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0xA3, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a']", | |
| "src/lib.rs split_hash: &str slicing at a non-char-boundary on non-ASCII 60-byte input", "src/lib.rs") | |
| k("versionize_fam", "RUSTSEC-2023-0030", "fam_entry", "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result<u32, u8>", | |
| "Reads entry i (< header_len) of a deserialised flexible-array struct whose header declares header_len entries; Err if the header length disagrees with the actual number of entries, never panic.", | |
| "panic", "model_of_std", | |
| "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result<u32, u8> {\n if i < header_len {\n Ok(entries[i])\n } else {\n Err(2)\n }\n}", | |
| "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result<u32, u8> {\n if header_len != entries.len() {\n return Err(1);\n }\n if i < header_len {\n Ok(entries[i])\n } else {\n Err(2)\n }\n}", | |
| "&[7u32, 8], 5usize, 3usize", "src/primitives.rs FamStructWrapper::deserialize: header length not checked against entries", "src/primitives.rs") | |
| def main(): | |
| cand = {} | |
| for l in open(CAND): | |
| r = json.loads(l); cand[r["adv_id"]] = r | |
| root = os.path.join(HERE, "kernels") | |
| for e in K: | |
| c = cand[e["adv"]] | |
| d = os.path.join(root, e["id"]) | |
| for ver in ("pre", "post"): | |
| os.makedirs(f"{d}/{ver}/src", exist_ok=True) | |
| open(f"{d}/{ver}/Cargo.toml", "w").write(f'[package]\nname = "k_{e["id"]}_{ver}"\nversion = "0.1.0"\nedition = "2021"\n\n[lib]\npath = "src/lib.rs"\n\n[workspace]\n') | |
| open(f"{d}/{ver}/src/lib.rs", "w").write(e[ver]) | |
| meta = dict(item_id=f"ker-{e['id']}", kernel=e["id"], advisory=e["adv"], crate=c["crate"], pre_version=c["pre_version"], post_version=c["post_version"], | |
| advisory_url=c["url"], title=c["title"], source_file=e["file"], function=e["fn"], signature=e["sig"], spec_doc=e["spec_doc"], | |
| bug_class=e["bug_class"], fidelity=e["fidelity"], extraction_note=e["note"], witness_args=e["witness"], | |
| labels={"buggy": f"{c['crate']}@{c['pre_version']}", "reference": f"{c['crate']}@{c['post_version']}"}) | |
| json.dump(meta, open(f"{d}/meta.json", "w"), indent=1) | |
| print(len(K), "kernels written to", root) | |
| if __name__ == "__main__": | |
| main() | |