--- a/sys/vfs/hammer2/hammer2_ondisk.c +++ b/sys/vfs/hammer2/hammer2_ondisk.c @@ -306,14 +306,24 @@ * volume, never the guest root fs */ dioerr = ENXIO; } - if (dioerr == 0) { + if (dioerr != 0) { + /* + * The volume's media size could not be + * determined (probe race, d_slice == NULL, + * raw fallback fail). This must not + * silently disable the containment check. + */ + hprintf("%s's media size could not be " + "determined, refusing to mount\n", + path); + return EINVAL; + } if (vol->size > part.media_size) { hprintf("%s's size 0x%016jx exceeds device size " "0x%016jx\n", path, (intmax_t)vol->size, part.media_size); return EINVAL; } - } } if (vol->size == 0) { hprintf("%s has size of 0\n", path); --- a/sys/vfs/hammer2/hammer2_io.c +++ b/sys/vfs/hammer2/hammer2_io.c @@ -353,6 +353,21 @@ dio->bp->b_flags &= ~B_AGE; /* dio->bp->b_debug_info2 = dio; */ } + + /* + * A short read completes WITHOUT B_ERROR under several media-EOF + * semantics: dscheck() clamps a straddling transfer to the device + * end (reducing b_bcount); a read starting exactly at EOF completes + * with B_INVAL and full b_resid; a vnode-backed device whose + * backing file shrank returns a 0-byte VOP_READ with uio_resid + * untouched. In all those cases part (or all) of the buffer is + * uninitialized kernel memory which must not be consumed as + * filesystem data. + */ + if (error == 0 && dio->bp && + (dio->bp->b_resid != 0 || dio->bp->b_bcount != dio->psize)) { + error = EIO; + } dio->error = error; /*