DF-5010 / fix.diff
diff --git a/sys/dev/virtual/vkernel/disk/vdisk.c b/sys/dev/virtual/vkernel/disk/vdisk.c index 4e7b3cdb..9b6a132a 100644 --- a/sys/dev/virtual/vkernel/disk/vdisk.c +++ b/sys/dev/virtual/vkernel/disk/vdisk.c @@ -305,6 +305,26 @@ vkd_doio(struct vkd_softc *sc, struct bio *bio) struct buf *bp = bio->bio_buf; int n; + /* + * The slice layer (dscheck()) normally bounds bios against + * d_media_blocks, but a driver must not blindly trust the + * generic layer. If an unbounded bio ever reaches this + * function, the COW-mode memcpy below reads/writes the host + * process mapping (sc->map_buf) out of bounds and the regular + * mode pwrite() silently extends the backing file (sparse + * growth). Reject out-of-range I/O here as well. + */ + if (bp->b_cmd == BUF_CMD_READ || bp->b_cmd == BUF_CMD_WRITE) { + if (bio->bio_offset < 0 || + bio->bio_offset >= sc->size || + (off_t)bp->b_bcount > sc->size - bio->bio_offset) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR | B_INVAL; + bp->b_resid = bp->b_bcount; + return; + } + } + switch(bp->b_cmd) { case BUF_CMD_READ: if (sc->map_buf) { @@ -339,6 +359,8 @@ vkd_doio(struct vkd_softc *sc, struct bio *bio) panic("vkd: bad b_cmd %d", bp->b_cmd); break; /* not reached */ } + if (n < 0) + n = 0; /* error: nothing was transferred */ if (bp->b_bcount != n) { bp->b_error = EIO; bp->b_flags |= B_ERROR; |