DragonFlyBSD Kernel Audit
DF-2903 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/subr_diskmbr.c
+++ b/sys/kern/subr_diskmbr.c
@@ -117,6 +117,16 @@
 	 */
 	if (info->d_media_blksize & DEV_BMASK)
 		return (EIO);
+	/*
+	 * The block size comes from the device (e.g. SCSI READ CAPACITY)
+	 * and must never be trusted: mbrinit() issues a synchronous read
+	 * of exactly one media block into a getpbuf_mem() pbuf whose
+	 * buffer is only MAXPHYS bytes.  Reject anything that cannot fit
+	 * (also rejects negative/0 values; d_media_blksize is signed).
+	 */
+	if (info->d_media_blksize < DEV_BSIZE ||
+	    info->d_media_blksize > MAXPHYS)
+		return (EIO);
 	if (info->d_media_size == 0)
 		return (EIO);
 
@@ -175,10 +185,18 @@
 			if (bootverbose)
 				kprintf("%s: Found \"Ontrack Disk Manager\" "
 					"on this disk.\n", sname);
-			bp->b_flags |= B_INVAL | B_AGE;
-			brelse(bp);
-			mbr_offset = 63;
-			goto reread_mbr;
+			/*
+			 * bp is a pbuf (getpbuf_mem) and must be
+			 * released with relpbuf(), not brelse().
+			 * Only take the re-read path once, otherwise
+			 * a crafted MBR with another Ontrack entry at
+			 * LBA 63 loops forever.
+			 */
+			if (mbr_offset == DOSBBSECTOR) {
+				relpbuf(bp, NULL);
+				mbr_offset = 63;
+				goto reread_mbr;
+			}
 		}
 	}