Bug 259280 - vtblk_maximum_segments can set nsegs too low, allowing panic on some non-aligned raw disk reads
Summary: vtblk_maximum_segments can set nsegs too low, allowing panic on some non-alig...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-bugs (Nobody)
Depends on:
Reported: 2021-10-19 17:32 UTC by Robert Morris
Modified: 2021-10-19 18:46 UTC (History)
2 users (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Robert Morris 2021-10-19 17:32:56 UTC
The virtio block device code's vtblk_maximum_segments() sets
nsegs to 3 if the device doesn't have VIRTIO_BLK_F_SEG_MAX
set. However, a 4096-byte read() to a non-page-aligned memory
address can then panic in vtblk_request_execute() due to
using up all the segments, in this code:

    if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
        error = sglist_append_bio(sg, bp);
        if (error || sg->sg_nseg == sg->sg_maxseg) {            
            panic("%s: bio %p data buffer too big %d",
                __func__, bp, error);

sg_nseg and sg_maxseg both end up as three, triggering
the panic.

I actually got this panic, on the tinyemu RISC-V simulator,
running e2fsck on a broken ext2 file system. Here's a
program that panics on tinyemu (but not qemu, which sets

int main() {
  int fd = open("/dev/vtbd0", 0);
  char buf1[4*4096];
  char *buf = buf1;
  while(((unsigned long)buf) % 4096) buf++;
  read(fd, buf + 0xd00, 4096);

panic: vtblk_request_execute: bio 0xffffffd0019ded38 data buffer too big 0
cpuid = 0
time = 1634664503
KDB: stack backtrace:
db_trace_self() at db_trace_self
db_trace_self_wrapper() at db_trace_self_wrapper+0x38
kdb_backtrace() at kdb_backtrace+0x2c
vpanic() at vpanic+0x148
panic() at panic+0x2a
vtblk_request_execute() at vtblk_request_execute+0x23a
vtblk_startio() at vtblk_startio+0x198
vtblk_strategy() at vtblk_strategy+0x66
g_disk_start() at g_disk_start+0x2b0
g_io_schedule_down() at g_io_schedule_down+0x32a
g_down_procbody() at g_down_procbody+0x58
fork_exit() at fork_exit+0x68
fork_trampoline() at fork_trampoline+0xa
KDB: enter: panic
[ thread pid 13 tid 100019 ]