DragonFlyBSD Kernel Audit
DF-0134 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/subr_disklabel64.c b/sys/kern/subr_disklabel64.c
--- a/sys/kern/subr_disklabel64.c
+++ b/sys/kern/subr_disklabel64.c
@@ -187,11 +187,40 @@
 		} else if (savecrc != crc32(&dlp->d_magic, dlpcrcsize)) {
 			msg = "disklabel64 corrupted, bad CRC";
 		} else {
-			dlp->d_crc = savecrc;
-			(*lpp).lab64 = kmalloc(sizeof(*dlp),
-					       M_DEVBUF, M_WAITOK|M_ZERO);
-			*(*lpp).lab64 = *dlp;
+			/*
+			 * Bound partitions against the slice.  The read path
+			 * historically checked only magic/npartitions/CRC and
+			 * copied the label verbatim, so a crafted label could
+			 * load partitions extending beyond the slice.  Reject
+			 * such labels.  (Do NOT check p_boffset >= d_pbase:
+			 * the legitimate RAW/whole-disk partition and the
+			 * kernel's own virgin label use p_boffset 0.)
+			 */
+			uint64_t slicebsize;
+			int p;
+
 			msg = NULL;
+			slicebsize = (uint64_t)sp->ds_size * info->d_media_blksize;
+			if (dlp->d_total_size > slicebsize)
+				msg = "disklabel64 corrupted, total size > slice";
+			for (p = 0; msg == NULL && p < dlp->d_npartitions; p++) {
+				struct partition64 *pp = &dlp->d_partitions[p];
+				if (pp->p_bsize == 0) {
+					if (pp->p_boffset != 0)
+						msg = "disklabel64 corrupted, "
+							      "partition out of bounds";
+					continue;
+				}
+				if (pp->p_boffset + pp->p_bsize > dlp->d_total_size)
+					msg = "disklabel64 corrupted, "
+						      "partition out of bounds";
+			}
+			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;