DF-0872 / fix.diff
diff --git a/sys/vfs/ntfs/ntfs_vfsops.c b/sys/vfs/ntfs/ntfs_vfsops.c --- a/sys/vfs/ntfs/ntfs_vfsops.c +++ b/sys/vfs/ntfs/ntfs_vfsops.c @@ -346,12 +346,44 @@ goto out; } + /* + * Validate the BPB-derived fields before dividing/shifting by them. + * A crafted boot sector can otherwise drive a divide-by-zero + * (CPU #DE -> non-resumable kernel trap -> panic) or an undefined + * shift (shift count >= type width). ntm_bpmftrec is later used as + * a divisor in ntfs_statfs()/ntfs_statvfs(), so it must be non-zero. + */ + if (ntmp->ntm_bps == 0 || ntmp->ntm_spc == 0) { + error = EINVAL; + dprintf(("ntfs_mountfs: invalid BPB (bps=%u spc=%u)\n", + ntmp->ntm_bps, ntmp->ntm_spc)); + goto out; + } { int8_t cpr = ntmp->ntm_mftrecsz; - if( cpr > 0 ) + if (cpr > 0) { ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; - else - ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; + } else { + /* + * cpr <= 0: MFT record size is 2^(-cpr) bytes; + * -cpr is the shift count and must lie in [0,31] to + * stay defined and fit in an int (cpr == INT8_MIN + * would otherwise yield 1 << 128, which is UB). + */ + int shift = -cpr; + if (shift < 0 || shift >= 32) { + error = EINVAL; + dprintf(("ntfs_mountfs: invalid mftrecsz %d\n", + cpr)); + goto out; + } + ntmp->ntm_bpmftrec = (1 << shift) / ntmp->ntm_bps; + } + } + if (ntmp->ntm_bpmftrec == 0) { + error = EINVAL; + dprintf(("ntfs_mountfs: zero bpmftrec\n")); + goto out; } dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, |