DragonFlyBSD Kernel Audit
DF-2910 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/subr_disklabel64.c	2026-09-03 07:23:47.324891985 +0000
+++ b/sys/kern/subr_disklabel64.c	2026-09-03 07:24:16.336521869 +0000
@@ -150,8 +150,10 @@
 	struct disklabel64 *dlp;
 	const char *msg;
 	uint32_t savecrc;
+	uint64_t slicebsize;
 	size_t dlpcrcsize;
 	size_t bpsize;
+	int p;
 	int secsize;
 
 	/*
@@ -180,18 +182,65 @@
 			     offsetof(struct disklabel64, d_magic);
 		savecrc = dlp->d_crc;
 		dlp->d_crc = 0;
+		slicebsize = (uint64_t)sp->ds_size * secsize;
 		if (dlp->d_magic != DISKMAGIC64) {
 			msg = "no disk label";
 		} else if (dlp->d_npartitions > MAXPARTITIONS64) {
 			msg = "disklabel64 corrupted, too many partitions";
 		} else if (savecrc != crc32(&dlp->d_magic, dlpcrcsize)) {
 			msg = "disklabel64 corrupted, bad CRC";
+		} else if (dlp->d_total_size > slicebsize) {
+			/*
+			 * DF-2910: structural validation.  dscheck() uses
+			 * these fields to route partition I/O with no
+			 * containment check of its own; an uncontained
+			 * p_boffset/p_bsize gives cross-slice access and,
+			 * because dscheck computes
+			 * (ds_offset + slicerel_secno) * dss_secsize with
+			 * mod-2^64 arithmetic, wraparound access to
+			 * arbitrary absolute media offsets (including the
+			 * MBR and the EROFS-protected label area itself).
+			 */
+			msg = "disklabel64 corrupted, total size";
+		} else if (dlp->d_bbase > slicebsize) {
+			/* d_bbase becomes ds_reserved; keep it contained */
+			msg = "disklabel64 corrupted, boot area";
 		} else {
-			dlp->d_crc = savecrc;
-			(*lpp).lab64 = kmalloc(sizeof(*dlp),
-					       M_DEVBUF, M_WAITOK|M_ZERO);
-			*(*lpp).lab64 = *dlp;
+			struct partition64 *pp;
+
 			msg = NULL;
+			for (p = 0; p < dlp->d_npartitions; ++p) {
+				pp = &dlp->d_partitions[p];
+				if (pp->p_bsize == 0) {
+					if (pp->p_boffset != 0) {
+						msg = "disklabel64 corrupted, "
+						      "partition";
+						break;
+					}
+					continue;
+				}
+				/*
+				 * Sector alignment and containment within
+				 * the slice.  Each term is bounded by
+				 * slicebsize first so the sum cannot wrap.
+				 */
+				if ((pp->p_boffset & (secsize - 1)) ||
+				    (pp->p_bsize & (secsize - 1)) ||
+				    pp->p_boffset > slicebsize ||
+				    pp->p_bsize > slicebsize ||
+				    pp->p_boffset + pp->p_bsize > slicebsize) {
+					msg = "disklabel64 corrupted, "
+					      "partition";
+					break;
+				}
+			}
+			if (msg == NULL) {
+				dlp->d_crc = savecrc;
+				(*lpp).lab64 = kmalloc(sizeof(*dlp),
+						       M_DEVBUF,
+						       M_WAITOK|M_ZERO);
+				*(*lpp).lab64 = *dlp;
+			}
 		}
 	}
 	bp->b_flags |= B_INVAL | B_AGE;