--- a/sys/vfs/ufs/ufs_vnops.c 2026-06-29 12:51:19.000000000 +0000 +++ ufs_vnops.c 2026-10-13 01:18:09.991161267 +0000 @@ -1654,13 +1654,27 @@ eoffset = bp->b_bcount; while (offset < eoffset) { + uint16_t on_disk_namlen; dp = (struct direct *)(bp->b_data + offset); if (dp->d_reclen <= 0 || (dp->d_reclen & 3) || offset + dp->d_reclen > bp->b_bcount) { error = EIO; break; } - if (offsetof(struct direct, d_name[dp->d_namlen]) > dp->d_reclen) { + /* + * DF-5807: in the old on-disk format the real namlen lives + * in the byte read as d_type; the byte read as d_namlen is + * the MSB. Validate the length that will actually be + * passed to vop_write_dirent() against d_reclen, or a + * crafted image causes an OOB source read. + */ +#if BYTE_ORDER == LITTLE_ENDIAN + on_disk_namlen = OFSFMT(vp) ? dp->d_type : dp->d_namlen; +#else + on_disk_namlen = dp->d_namlen; +#endif + if (offsetof(struct direct, d_name[on_disk_namlen]) > + dp->d_reclen) { error = EIO; break; } @@ -1671,13 +1685,13 @@ #if BYTE_ORDER == LITTLE_ENDIAN if (OFSFMT(vp)) { retval = vop_write_dirent(&error, uio, - dp->d_ino, dp->d_namlen, dp->d_type, + dp->d_ino, dp->d_namlen, on_disk_namlen, dp->d_name); } else #endif { retval = vop_write_dirent(&error, uio, - dp->d_ino, dp->d_type, dp->d_namlen, + dp->d_ino, dp->d_type, on_disk_namlen, dp->d_name); } if (retval)