DragonFlyBSD Kernel Audit
DF-0787 / run.log
← back to finding ↓ download raw
===== 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)