DragonFlyBSD Kernel Audit
DF-0726 / run.log
← back to finding ↓ download raw
=== DF-0726 baseline race on UNPATCHED kernel (#0, 6.5-DEVELOPMENT Thu Jul 2 06:02:54 UTC 2026) ===

Attempt 1 (reader.c, 1 thread, 25s writer if_tap kldload/kldunload):
  reader: 38,453,248 iters, total=7 (consistent, no EFAULT/ENOMEM)
  writer: 4598 kldload/kldunload cycles of if_tap.ko
  result: guest UP, no panic, no new boot.log content
  reader stderr tail:
    [reader] 38387712 iters, total=7
    [reader] 38404096 iters, total=7
    [reader] 38420480 iters, total=7
    [reader] 38436864 iters, total=7
    [reader] 38453248 iters, total=7

Attempt 2 (reader2.c, 8 threads, madvise-widened, 55s writer 3-module cycle):
  reader: 114,777,878 total iters across 8 threads
  writer: 9411 iterations x 3 modules (if_tap/if_vlan/if_gre) = ~28k load/unload cycles
  result: guest UP, no panic, no new boot.log content
  reader stderr: [reader2] 114777878 total iters across 8 threads

Attempt 3 (reader2.c, 16 threads, madvise-widened, 170s writer 5-module cycle):
  reader: 151,259,361 total iters across 16 threads
  writer: ~170s cycling if_tap/if_vlan/if_gre/if_bridge/if_wg (writer killed by tool timeout but reader confirmed alive)
  result: guest UP, no panic, no new boot.log content
  reader stderr: [reader2] 151259361 total iters across 16 threads

TOTAL across 3 attempts: ~265M+ reader iterations, ~50k+ writer load/unload cycles, ZERO panics.

=== Code-level trace (the race IS real, just too narrow to hit) ===
  Reader (unprivileged): SIOCIFGCLONERS -> if_clone_list() at sys/net/if_clone.c:201-230
    - line 207: reads if_cloners_count (NO LOCK)
    - line 216: reads if_cloners_count again (NO LOCK)
    - line 219-221: LIST_FIRST + LIST_FOREACH traversal (NO LOCK)
    - line 223: reads ifc->ifc_name (NO LOCK)
    Reachability: sys/net/if.c:2017-2018, NO caps_priv_check (confirmed unprivileged)
  Writer (root, kldload/kldunload):
    if_clone_attach() at if_clone.c:141-183:
      - line 147: LIST_FOREACH dup check (NO LOCK)
      - line 166: LIST_INSERT_HEAD (NO LOCK, before ifnet_lock at 169)
      - line 167: if_cloners_count++ (NO LOCK)
    if_clone_detach() at if_clone.c:189-195:
      - line 192: LIST_REMOVE (NO LOCK)
      - line 193: kfree(ifc->ifc_units) (NO LOCK)
      - line 194: if_cloners_count-- (NO LOCK)
    if_clone_lookup() at if_clone.c:296-306:
      - line 300: LIST_FOREACH (NO LOCK), called from if_clone_create:67 + if_clone_destroy:116
  Page unmap (the UAF sink): linker_file_unload() -> file->ops->unload() ->
    link_elf_obj_unload_file() at sys/kern/link_elf_obj.c:904 vm_map_remove(kernel_map, ...)

  The race window is between if_clone_detach() LIST_REMOVE (if_clone.c:192) and
  vm_map_remove() (link_elf_obj.c:904). During this window (which spans the rest
  of the module's MOD_UNLOAD handler + SYSUNINITs + sysctl unregister), a reader
  holding a pointer to the detaching ifc can dereference freed/unmapped memory.
  The reader's vulnerable window per iteration is ~50ns (between LIST_NEXT returning
  &tap_cloner and the subsequent ifc->ifc_name read), making the race extremely
  narrow despite the writer's wider unload window.

=== Verdict ===
  status: not_reproduced (race confirmed in code, too narrow to trigger in practice)
  impact: none (no panic observed; potential impact is panic/DoS if race were hit)
  The writer requires root (kldload/kldunload), so this is NOT independently unprivileged.