DF-0787 / run.log
===== DF-0787: unbounded attribute walk in ntfs_loadntnode =====
LIVE KERNEL REPRODUCTION (default GENERIC kernel #0, unpatched ntfs.ko):
------------------------------------------------------------------------
Trigger (run as root on guest):
vnconfig -c vn0 /root/ntfs_loop.img
mount_ntfs -o ro /dev/vn0 /mnt/ntfs
Result: kernel PANIC. The mount(2) syscall never returns; the guest drops
to the DDB prompt. Identical panic for ntfs_loop.img, ntfs_oob_a.img, and
ntfs_oob_r.img — all three malformed-image variants hit the same unbounded
walk at sys/vfs/ntfs/ntfs_subr.c:305-320. Only cpuid varies.
Serial-log panic signature (from dfbsd-qemu/boot.log):
panic: NTFS vattr: malloc limit exceeded
cpuid = 5
Trace beginning at frame 0xfffff80117fe2e30
_kmalloc() at _kmalloc+0xb09 0xffffffff806578c9
_kmalloc() at _kmalloc+0xb09 0xffffffff806578c9
ntfs_attrtontvattr() at ntfs_attrtontvattr+0x35 0xffffffff82602685
ntfs_loadntnode() at ntfs_loadntnode+0x178 0xffffffff82604278
ntfs_vgetex() at ntfs_vgetex+0x1ec 0xffffffff826010ac
ntfs_vget() at ntfs_vget+0x29 0xffffffff82601219
Debugger("panic")
Stopped at Debugger+0x7c: movb $0,0xbdaf09(%rip)
db>
USERSPACE HARNESS (deterministic complement, run as maxx uid 1001):
-------------------------------------------------------------------
The harness replicates the exact walk from ntfs_subr.c:305-320 against a
4096-byte record backed by a guard page, so any OOB read faults and any
reclen==0 spins (caught by an iteration cap that the kernel does NOT have).
--- BUGGY walk (mirrors kernel behaviour on default GENERIC #0) ---
--- BUGGY ---
mode=clean apply_fix=0 -> rc=0 clean exit (end-of-attributes reached)
mode=loop apply_fix=0 -> rc=1 ITERATION CAP HIT -> would be infinite loop in kernel
mode=oob_attroff apply_fix=0 -> rc=1 ITERATION CAP HIT -> would be infinite loop in kernel
mode=oob_reclen apply_fix=0 -> rc=2 SIGSEGV -> OOB read past record (into adjacent slab in kernel)
--- WITH FIX ---
mode=clean apply_fix=1 -> rc=0 clean exit (end-of-attributes reached)
mode=loop apply_fix=1 -> rc=-1 FIX REJECTED input ( EINVAL in kernel)
mode=oob_attroff apply_fix=1 -> rc=-1 FIX REJECTED input ( EINVAL in kernel)
mode=oob_reclen apply_fix=1 -> rc=-1 FIX REJECTED input ( EINVAL in kernel)