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