UTF-8 Soundness Violation: from_utf8_unchecked on unvalidated bytes in all 6 SIMD backends
## 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 条评论