DF-3048 / verdict.json
{ "finding_id": "DF-3048", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "s_inodes_count is never validated against s_groups_count*s_inodes_per_group at mount; a crafted dirent with ino in (gcount*ipg, icount] makes ext2_vget/ino_to_fsba index fs->e2fs_gd[(ino-1)/ipg] far out of bounds. Reproduced: fatal kernel page fault with RIP in e2fs_gd_get_i_tables from a single stat() of the patched 'lost+found' entry. Fixed module rejects the image at mount.", "exploit_chain": "crafted ext2 image (icount=0x7ffffff0, dirent ino=0x40000002) -> root/usermount mount -> stat /mnt/lost+found -> ext2_lookup:809 passes (ino<=icount) -> VFS_VGET -> ext2_vget:1358 ino_to_fsba -> fs->e2fs_gd[1048576] (64MB past 1KB alloc) -> kernel page fault -> panic. Wild-read primitive: cg=(ino-1)/ipg attacker-chosen; unmapped->panic (demonstrated), mapped->garbage i_tables steers subsequent bread (not pursued to leak).", "evidence": "run.log (full session), panic.txt (console: RIP=e2fs_gd_get_i_tables), fix_run.txt (fixed module: mount EINVAL, guest alive)", "kernel_refs": ["sys/vfs/ext2fs/ext2_vfsops.c:606", "sys/vfs/ext2fs/ext2_vfsops.c:1358", "sys/vfs/ext2fs/fs.h:111", "sys/vfs/ext2fs/ext2_lookup.c:809", "sys/vfs/ext2fs/ext2_inode_cnv.c:116"], "poc_changes": "seed sketch had no working image: crafted with mke2fs 1.47 (-O ^metadata_csum,^64bit, -I 128), patched s_inodes_count and the root-dir lost+found dirent inode directly; guest lacks vnconfig so vntool.c (VNIOCATTACH) was written; mount(8) needed no changes.", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 95, "guest_dirty": 0, "build_cmd": "python3 craft.py df3048.img ; cc -O2 -o /root/vntool /root/vntool.c", "run_cmd": "kldload ext2fs; /root/vntool attach 0 /root/df3048.img; mount -t ext2fs -o ro /dev/vn0 /mnt/e2; stat /mnt/e2/lost+found", "code_hash": "3b9c6bab3c0f24d79cbf1b11f34ab8d40ae0b428a2c9a0077b2d79b6a4723944", "notes": "impact classified panic (reliable DoS from mounted image; OOB read primitive characterized). fhtovp path is NOT affected (bounds by gcount*ipg). Fix validated on rebuilt ext2fs.ko: mount denied EINVAL, no panic; pristine RW mount regression-checked.", "recommended_fix": "reject s_inodes_count > (uint64_t)gcount * ipg in ext2_compute_sb_data()", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 (same kernel; ext2fs.ko module rebuilt with fix.diff hunk 2, 2026-09-05)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "with the clamp the crafted image is rejected at mount (EINVAL 'inode count exceeds groups x inodes per group'); stat is harmless; guest healthy; identical-geometry reload and pristine RW mounts still work (regression checks in DF-3047/fix_run.txt console capture).", "fix_evidence": "findings/poc/DF-3048/fix_run.txt; findings/poc/DF-3047/fix.diff (hunk 2); fix console capture findings/poc/DF-3047/fix_run.txt" } |