โฌข DragonFlyBSD Kernel Audit
DF-0807 / run.log
โ† back to finding โ†“ download raw
+ ./harness
=== DF-0807 dirfs_readdir premature-dp-advancement harness ===
Transcription of sys/vfs/dirfs/dirfs_vnops.c:1277-1286
Bug: loop body executes `dp = dpn` BEFORE the for-increment
     `bytes -= _DIRENT_DIRSIZ(dp)`, so after the last valid
     entry the increment derefs dp->d_namlen past the buffer
     (OOB read) and the next iteration copies OOB bytes to the
     user readdir sink via vop_write_dirent (info leak).

Scenario: bufsiz=512  name_len=8 (16 entries)
  [guard-page variant] bufsiz=512 name_len=8
    filled bytes=512 (== bufsiz ? YES โ€” dp advances PAST allocation)
    BUGGY loop:  FAULT -> OOB READ CONFIRMED in for-increment `bytes -= DIRSIZ(dp)` (entries=16 bytes_after=32)
    FIXED loop:  no fault (loop terminated cleanly) (entries=16 bytes_after=0)
  [leak-zone variant] bufsiz=512 name_len=8
    filled bytes=512 (== bufsiz ? YES), leak zone @ 0x8004a3000, fake d_namlen=7 (DIRSIZ=24 < rec=32)
    BUGGY loop:  entries=27 bytes_after=-43944 ; sink has OOB marker ? YES -> INFO LEAK CONFIRMED
      leaked marker at sink offset 528: 'HEAP-LE'
    FIXED loop:  entries=16 bytes_after=0 ; sink has OOB marker ? no (clean termination)

Scenario: bufsiz=1024 name_len=8 (32 entries)
  [guard-page variant] bufsiz=1024 name_len=8
    filled bytes=1024 (== bufsiz ? YES โ€” dp advances PAST allocation)
    BUGGY loop:  FAULT -> OOB READ CONFIRMED in for-increment `bytes -= DIRSIZ(dp)` (entries=32 bytes_after=32)
    FIXED loop:  no fault (loop terminated cleanly) (entries=32 bytes_after=0)
  [leak-zone variant] bufsiz=1024 name_len=8
    filled bytes=1024 (== bufsiz ? YES), leak zone @ 0x8004ab000, fake d_namlen=7 (DIRSIZ=24 < rec=32)
    BUGGY loop:  entries=43 bytes_after=-43944 ; sink has OOB marker ? YES -> INFO LEAK CONFIRMED
      leaked marker at sink offset 1040: 'HEAP-LE'
    FIXED loop:  entries=32 bytes_after=0 ; sink has OOB marker ? no (clean termination)

Scenario: bufsiz=2048 name_len=8 (64 entries)
  [guard-page variant] bufsiz=2048 name_len=8
    filled bytes=2048 (== bufsiz ? YES โ€” dp advances PAST allocation)
    BUGGY loop:  FAULT -> OOB READ CONFIRMED in for-increment `bytes -= DIRSIZ(dp)` (entries=64 bytes_after=32)
    FIXED loop:  no fault (loop terminated cleanly) (entries=64 bytes_after=0)
  [leak-zone variant] bufsiz=2048 name_len=8
    filled bytes=2048 (== bufsiz ? YES), leak zone @ 0x8004b3000, fake d_namlen=7 (DIRSIZ=24 < rec=32)
    BUGGY loop:  entries=75 bytes_after=-43944 ; sink has OOB marker ? YES -> INFO LEAK CONFIRMED
      leaked marker at sink offset 2064: 'HEAP-LE'
    FIXED loop:  entries=64 bytes_after=0 ; sink has OOB marker ? no (clean termination)

Scenario: bufsiz=4096 name_len=8 (128 entries, dirfs clamp)
  [guard-page variant] bufsiz=4096 name_len=8
    filled bytes=4096 (== bufsiz ? YES โ€” dp advances PAST allocation)
    BUGGY loop:  FAULT -> OOB READ CONFIRMED in for-increment `bytes -= DIRSIZ(dp)` (entries=128 bytes_after=32)
    FIXED loop:  no fault (loop terminated cleanly) (entries=128 bytes_after=0)
  [leak-zone variant] bufsiz=4096 name_len=8
    filled bytes=4096 (== bufsiz ? YES), leak zone @ 0x8004bb000, fake d_namlen=7 (DIRSIZ=24 < rec=32)
    BUGGY loop:  entries=139 bytes_after=-43944 ; sink has OOB marker ? YES -> INFO LEAK CONFIRMED
      leaked marker at sink offset 4112: 'HEAP-LE'
    FIXED loop:  entries=128 bytes_after=0 ; sink has OOB marker ? no (clean termination)

=== SUMMARY ===
Vulnerable dirfs_readdir loop:
  - HEAP OOB READ in the for-increment after the last valid entry
    (reads d_namlen from the slab chunk / redzone adjacent to buf)
  - KERNEL HEAP INFO LEAK via the next iteration's vop_write_dirent
    (bcopy of attacker-recognizable d_ino/d_type/d_namlen/d_name
     from past the allocation into the user readdir result)
Fixed loop (remove `dp = dpn` from body):
  - bytes correctly decrements by the size of the just-processed entry
  - loop terminates with bytes == 0 after the last valid entry
  - no OOB read, no leak
Reachability: vkernel64-only (sys/platform/vkernel64/conf/files)
Realistic ceiling: vkernel heap info leak (read-only primitive)
RUN_EXIT=0