Skip to content

fix(virtio): support scatter-gather buffers in virtio-blk - #544

Open
Lencerf wants to merge 1 commit into
google:mainfrom
Lencerf:fix/blk-critical
Open

Lencerf wants to merge 1 commit into
google:mainfrom
Lencerf:fix/blk-critical

Conversation

@Lencerf

@Lencerf Lencerf commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes descriptor framing and malformed-descriptor handling in virtio-blk (alioth/src/virtio/dev/blk.rs), per VirtIO 1.4 Sec 2.7.4 and Sec 5.2.6.

The FLUSH durability fix that was also in this PR is now in #545. Both PRs touch the same lines in VirtioMio::handle_queue(), so whichever merges second needs a rebase.

  • Reshape DescChain in place by consuming the 16-byte Request header across arbitrary readable slice boundaries and isolating the trailing 1-byte status slice in writable, rejecting malformed buffer layouts with InvalidBuffer.
  • Check sector offsets with checked arithmetic and against the capacity, completing out-of-range reads and writes with Status::IOERR. A driver MUST NOT access beyond the capacity (Sec 5.2.6.1), and a write beyond it previously extended the disk image file.
  • Ignore any data in a FLUSH request, which a driver SHOULD NOT but may include (Sec 5.2.6.1).
  • Support multi-segment IN/OUT transfers sequentially in VirtioMio and via opcode::Readv/opcode::Writev in VirtioIoUring.
  • Complete io_uring requests from the reshaped DescChain without re-parsing the guest Request header from RAM (eliminating a guest TOCTOU unreachable!() panic) and report short reads/writes as Status::IOERR.
  • Propagate InvalidBuffer out of VirtioMio::handle_queue() so malformed descriptor chains fail the worker (DEVICE_NEEDS_RESET) instead of completing with len = 0 and leaving a pre-zeroed guest status byte as Status::OK.
  • NUL-pad VIRTIO_BLK_T_GET_ID responses up to VIRTIO_BLK_ID_SIZE (20 bytes) and add unit tests in blk_test.rs.

cargo +nightly fmt --check, cargo clippy --all-targets -D warnings on x86_64-unknown-linux-gnu/musl, aarch64-unknown-linux-gnu and aarch64-apple-darwin, and cargo test --workspace pass locally.

@coveralls

coveralls commented Nov 11, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 42962745661

Coverage increased (+1.8%) to 45.634%

Details

  • Coverage increased (+1.8%) from the base build.
  • Patch coverage: 6 uncovered changes across 1 file (164 of 170 lines covered, 96.47%).
  • 2 coverage regressions across 1 file.

Uncovered Changes

File Changed Covered %
alioth/src/virtio/dev/blk.rs 170 164 96.47%

Coverage Regressions

2 previously-covered lines in 1 file lost coverage.

File Lines Losing Coverage Coverage
alioth/src/virtio/dev/vsock/uds_vsock.rs 2 81.22%

Coverage Stats

Coverage Status
Relevant Lines: 16574
Covered Lines: 7350
Line Coverage: 44.35%
Relevant Branches: 1796
Covered Branches: 1033
Branch Coverage: 57.52%
Branches in Coverage %: Yes
Coverage Strength: 910.0 hits per line

💛 - Coveralls

@Lencerf
Lencerf force-pushed the fix/blk-critical branch 2 times, most recently from 819e9f5 to 1a38745 Compare November 11, 2026 04:49
Block::handle_desc() previously required the 16-byte Request header to
occupy its own readable descriptor, the 1-byte status to occupy its own
writable descriptor, and IN/OUT payloads to consist of a single
descriptor. This rejected multi-segment scatter-gather block I/O as well
as split headers and coalesced header/data/status descriptors, violating
VirtIO 1.4 Sec 2.7.4 ("The device MUST NOT make assumptions about the
particular arrangement of descriptors").

Reshape DescChain in place by consuming the 16-byte Request header from
the front of readable and isolating the trailing 1-byte status slice in
writable, rejecting malformed buffer layouts with InvalidBuffer:

- Validate sector offsets with checked arithmetic and against the
  capacity, completing out-of-range reads and writes with
  Status::IOERR. A driver MUST NOT access beyond the capacity (Sec
  5.2.6.1), and a write beyond it previously extended the disk image
  file.
- Ignore any data in a FLUSH request, which a driver SHOULD NOT but may
  include (Sec 5.2.6.1).
- In VirtioMio, transfer multi-segment IN/OUT payloads sequentially at
  advancing file offsets, and propagate InvalidBuffer out of
  handle_queue() so malformed descriptors fail the worker instead of
  completing with len == 0 (which left a pre-zeroed status byte as
  Status::OK).
- In VirtioIoUring, submit Readv and Writev against the reshaped
  DescChain iovec slices, and complete requests from the reshaped chain
  without re-reading the guest Request header (avoiding a guest TOCTOU
  panic) while reporting short reads and writes as Status::IOERR.
- NUL-pad VIRTIO_BLK_T_GET_ID responses to VIRTIO_BLK_ID_SIZE (20 bytes)
  per VirtIO 1.4 Sec 5.2.6.

Add unit tests covering scatter-gather I/O, split and coalesced framing,
FLUSH/GET_ID/RO/UNSUPP/capacity/overflow handling, malformed descriptor
propagation, and deferred completion.

Fixes: 01f5cac ("feat(block): impl raw file backed virtio-block dev")
Fixes: 213e216 ("refactor(blk): split descriptor handler to 2 parts")
Fixes: 342e016 ("feat(blk): io_uring based virtio-blk device")
Signed-off-by: Changyuan Lyu <changyuanl@google.com>
@Lencerf Lencerf changed the title fix(virtio): fix virtio-blk FLUSH sync and scatter-gather framing fix(virtio): support scatter-gather buffers in virtio-blk Nov 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants