ITADN

UTF-8 Soundness Violation: from_utf8_unchecked on unvalidated bytes in all 6 SIMD backends

#453Openma-moon 创建于 2026-05-27
M
ma-mooncommented
## Summary simd-json's `parse_str` function in **all 6 SIMD backends** (avx2, native, neon, portable, sse42, simd128) calls `std::str::from_utf8_unchecked` on byte sequences that have **NOT been validated as valid UTF-8**. This produces invalid `&str` values, violating Rust's core language safety guarantee (soundness violation). The crate already contains a `utf8check` module with SIMD-accelerated UTF-8 validation, but this module is **never called** on the string parsing path — it is only used for stage-1 structural character detection. This strongly suggests the omission is unintentional. ## Details The fast path in `parse_str` only filters bytes that are `"`, `\`, or control characters (0x00-0x1F). It does **not** validate multi-byte UTF-8 sequences. Any invalid UTF-8 sequences — bare continuation bytes (0x80-0xBF), lone surrogates (0xED 0xA0-0xBF), overlong encodings — pass through and are wrapped in `&str` without validation. ## Affected Call Sites (v0.17.0, 12 call sites across 6 backends) | File | Line | Pattern | |------|:----:|---------| | `impls/avx2/deser.rs` | 76 | `from_utf8_unchecked(from_raw_parts(input.add(idx), len))` | | `impls/avx2/deser.rs` | 133 | `from_utf8_unchecked(from_raw_parts(...))` | | `impls/native/deser.rs` | 30 | `from_utf8_unchecked(from_raw_parts(input, src_i))` | | `impls/native/deser.rs` | 107 | `from_utf8_unchecked(from_raw_parts(input, dst_i))` | | `impls/neon/deser.rs` | 91, 151 | same pattern | | `impls/portable/deser.rs` | 53, 106 | same pattern | | `impls/sse42/deser.rs` | ~67, ~124 | same pattern | | `impls/simd128/deser.rs` | ~60, ~119 | same pattern | ## Why This Is a Rust Soundness Violation Rust's guarantee that `&str` is always valid UTF-8 is a core safety invariant. Violating it is **undefined behavior**: - `s.chars()` — iterator assumes valid UTF-8, may read past buffer or produce wrong results - `s.contains()` / `s.starts_with()` — pattern matching on invalid UTF-8 is UB - `format!("{}", s)` / `println!` — may panic or corrupt output ## Proof of Concept ```rust use simd_json::BorrowedValue; fn main() { let input = b"{\"a\": \"\xff\xfe\"}"; let mut vec = input.to_vec(); vec.extend(std::iter::repeat(0).take(64)); // SIMDJSON_PADDING let result: Result<BorrowedValue, _> = simd_json::to_borrowed_value(&mut vec); if let Ok(BorrowedValue::Object(map)) = result { if let Some(BorrowedValue::String(s)) = map.get("a") { // `s` is an invalid &str — UB in safe Rust code println!("String bytes: {:?}", s.as_bytes()); } } } ``` ## Suggested Fix **Option A (recommended)**: Call the existing `utf8check` module after isolating string content. It's already SIMD-optimized and present in the codebase. **Option B**: Use `std::str::from_utf8` instead of `from_utf8_unchecked`. ## Credit ForgeCore (independent security researcher)
0 条评论