Skip to content

fix(encoding): backport corruption-safety fixes to release/v2.0 - #8151

Draft
Xuanwo wants to merge 7 commits into
release/v2.0from
backport/8138-8144-to-release-v2-0
Draft

fix(encoding): backport corruption-safety fixes to release/v2.0#8151
Xuanwo wants to merge 7 commits into
release/v2.0from
backport/8138-8144-to-release-v2-0

Conversation

@Xuanwo

@Xuanwo Xuanwo commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Backport the corruption-safety fixes from:

The v2.0 stable line still reaches the vulnerable VariableFullZip length-prefix parser and unchecked variable-width offset paths through the default reader.

Release-specific adaptation: use the v2.0 error-construction and synchronous reader APIs; retain native V2.1/V2.2 regression coverage only.

Release CI note: the original v2.0 build-no-lock failure was a resolver/toolchain mismatch. The branch pins its normal workspace toolchain to Rust 1.91, while this job must resolve and build the latest dependency graph. This backport includes the branch-native stable override needed to bypass that file override for build-no-lock only; the independent MSRV job remains pinned. No AWS manifest pins or lockfile changes are included.

Validation:

  • cargo fmt --all -- --check: passed
  • Targeted lance-encoding/lance-file corruption regression tests: passed (1 + 12 + 1 + 1 + 5 + 4 tests)
  • cargo clippy --all --tests --benches -- -D warnings: blocked by pre-existing v2.0 rust/lance-file/benches/reader.rs diagnostics in the non-Linux stub (unused path parameter and println!); this file is unchanged by the backport
  • rust.yml YAML, rustup override version check, and git diff checks: passed
  • Final GitHub build-no-lock: SUCCESS (job 91597342718)
  • Final GitHub mac-build (stable): baseline failure in unchanged IVF code; 1016 passed and 1 failed in index::vector::ivf::v2::tests::test_build_ivf_pq_4bit::case_3 with recall: 0.68 (job 91597342756). This is a flaky test failure unrelated to the backport.
  • Final GitHub linux-build: baseline nightly/tooling failure before Lance compilation; ethnum 1.5.2 fails with E0512 under the current nightly (job 91597342702). No product workaround is included.
  • Python and cargo-deny failures are baseline/tooling exceptions outside the create-rc workflow dependency graph; no optional Python extras were pinned here

professor-moody and others added 4 commits August 3, 2026 04:36
…er::unzip (#8138)

`parse_length` reads the length prefix out of the page buffer with
`get_unchecked`, and the only thing between it and the end of the buffer
is a `debug_assert!`:

```rust
// Safety: Data should have at least bytes_per_length bytes remaining
debug_assert!(databuf.len() >= bytes_per_length);
let length = unsafe { Self::parse_length(databuf, in_bits_per_length) };
```

There is no `[profile.release]` override in the workspace `Cargo.toml`,
so `debug-assertions` defaults to false in release and that assertion is
not present in the published wheels.

The loop it sits in continues on `while !databuf.is_empty()`, so it
enters the body with as little as one byte remaining. `parse_length`
then reads up to eight. A page whose item walk ends with a partial
trailing item therefore reads past the end of the buffer.

Reproduced on x86-64 with `-Zsanitizer=address` on a release build,
driving the real `VariableFullZipDecoder::new`:

```
ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 8 at 0x7b9989be1017
  #0 <lance_encoding::...::VariableFullZipDecoder>::new
0x7b9989be1017 is located 3 bytes after 4-byte region [0x...1010,0x...1014)
```

A well-formed control buffer is clean in the same run.

The payload read one line below the call site is already bounds checked
and panics on malformed input:

```rust
unzipped_data.extend_from_slice(&databuf[..length as usize]);
```

So a truncated item already fails cleanly on the payload path. Only the
length read was inconsistent. This makes the two match by using safe
indexing in `parse_length`, which lets the `unsafe` block and the
`debug_assert!` both go away.

On valid input the behaviour is unchanged. On a truncated trailing item
the result is the same clean panic the payload path already produces,
rather than an out-of-bounds read.

Two, per the contributing guide:

- `variable_full_zip_wellformed_length_prefix` decodes a well-formed
prefix
- `variable_full_zip_truncated_length_prefix_is_rejected` is
`#[should_panic]` and covers the case above

Both pass, and the crate's existing suite is unaffected (520 passing
before and after).

I have not established that a `.lance` file produced by the writer can
reach this state. Truncating a data file is rejected earlier by the I/O
range check, and a sweep of in-place single-byte edits either read
cleanly, were rejected by that same check, or panicked in safe code
further along in decode. So I am not claiming this is reachable from a
crafted dataset, and I am filing it as hardening rather than as a
security report.

The case for the change does not depend on that: an `unsafe` read whose
only guard is compiled out of release builds is worth removing on its
own, particularly when the adjacent read of the same buffer is already
checked.

Not part of this change, and not something I have shown to be a bug, but
it looked odd while reading. The length is read using
`in_bits_per_length` and the cursor is then advanced by
`bytes_per_offset`, which comes from `out_bits_per_offset`:

```rust
let length = ... parse_length(databuf, in_bits_per_length);
databuf = &databuf[bytes_per_offset..];
```

Those are equal in the common case, so this may well be deliberate.
Flagging it only in case the asymmetry is unintentional.

---------

Co-authored-by: Xuanwo <github@xuanwo.io>
@github-actions github-actions Bot added A-encoding Encoding, IO, file reader/writer bug Something isn't working and removed A-encoding Encoding, IO, file reader/writer labels Aug 3, 2026
@github-actions github-actions Bot added A-encoding Encoding, IO, file reader/writer A-ci CI / build workflows labels Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ci CI / build workflows A-encoding Encoding, IO, file reader/writer bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants