DragonFlyBSD Kernel Audit
DF-2663 / fix2663.diff
← back to finding ↓ download raw
--- a/sys/vfs/hammer2/hammer2_ondisk.c
+++ b/sys/vfs/hammer2/hammer2_ondisk.c
@@ -281,13 +281,24 @@
 		}
 		/* check volume size vs block device size */
 		if (VOP_IOCTL(vol->dev->devvp, DIOCGPART, (void*)&part, 0,
-			      curthread->td_ucred , NULL) == 0) {
-			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;
-			}
+			      curthread->td_ucred , NULL) != 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: a forged volu_size beyond the backing
+			 * device would be accepted and reads past the real
+			 * device end resolve to short reads.
+			 */
+			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;
 
 	/*