DF-2910 / fix.diff
--- 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; |