DragonFlyBSD Kernel Audit
DF-0874 / fix_run.log
← back to finding ↓ download raw
=== DF-0874 Phase-8 fix validation (ntfs.ko hot-swap, kernel #0 unchanged) ===

Kernel : DragonFly 6.5-DEVELOPMENT #0 (GENERIC, INVARIANTS ON) -- UNCHANGED
Module : /boot/kernel/ntfs.ko
  unpatched sha256 : aa8d83843beedc5b60956ee4afa048f62a6d96d5396a8fb660490ab83af391d4
  patched   sha256 : 846888df98030684633f83b061abd1b87f3272f023162e6a8a653a1af0ebb1d3
fix.diff: bounds the ntfs_readdir indexentry walk (vnops.c:585) against
          fp->f_dirblbuf/f_dirblsz + rejects reclen < ie_fname offset.

------------------ BEFORE (unpatched ntfs.ko, kernel #0) ------------------
Trigger image: ntfs_reclen0.img (root $INDEX_ROOT entry[0] reclen=0, no LAST)
  $ ./trigger /mnt/t
  [+] opened /mnt/t; reading dirents ...
    dirent[0]: .. (faked)
    dirent[1]: d_ino=0x48484848 d_name='HHHH'
    dirent[2]: d_ino=0x48484848 d_name='HHHH'
    ... (walk never advances because NTFS_NEXTREC(iep)=iep+0=iep) ...
    dirent[256]: d_ino=0x48484848 d_name='HHHH'
  [+] readdir returned 257 entries            <-- FLOOD: 256 duplicate dirents

Trigger image: ntfs_oob.img (entry[0] reclen=0xFFF0, no LAST)
  [+] readdir returned 2 entries              <-- entry[0] processed, then OOB
                                                read at rdbuf+0xFFF0 (mapped
                                                kmem, masked by LAST-bit in
                                                residue on INVARIANTS kernel)

Harness (code-level, deterministic):
  ./harness 0xFFF0 0 1
    => BUG CONFIRMED: ntfs_readdir dereferenced index entries 1 time(s) PAST
       the INDEX_ROOT valid data (rdsize=122) using attacker reclen=0xfff0.
  ./harness 0x60 0 1
    => BUG CONFIRMED: 2 OOB derefs past rdsize.
  ./harness 0x0 0 1
    => reclen==0 at off=32 -> kernel infinite-loop hang (DoS).

------------------ AFTER (patched ntfs.ko, kernel #0) ------------------
Trigger image: ntfs_reclen0.img (same)
  $ ./trigger /mnt/t
  [!] readdir returned 0 entries; errno=22 (Invalid argument)
                                              <-- EINVAL: fix rejects reclen=0
                                                  (< ie_fname offset); flood GONE

Trigger image: ntfs_oob.img (same)
  [+] readdir returned 2 entries              <-- entry[0] processed in-bounds;
                                                  OOB advance to +0xFFF0
                                                  PREVENTED by bounds check
                                                  (loop condition fails)

Regression: clean image (3 proper entries + LAST)
  [+] readdir returned 4 entries (.. HELLO WORLD FOO)
                                              <-- no regression on valid images

=== VERDICT: fix closes the bug (flood eliminated, OOB walk prevented) ===
           without regressing valid NTFS images.