# DF-5133 — VERDICT: reproduced (unprivileged kernel NULL-call panic), fix validated

## What was run

1. Built the `dmabugdemo` kmod against the stock guest kernel
   (DragonFly 6.5-DEVELOPMENT #0, Thu Jul 2 06:02:54 UTC 2026, x86_64).
   The kmod resolves the REAL `dma_buf_export` / `dma_buf_fd` symbols from
   the stock `/boot/kernel/drm.ko` and exposes three CTLFLAG_ANYBODY sysctl
   nodes. `hw.dmabug.panic` (fireable by uid 65534) creates a genuine dma-buf
   fd in the CALLER's fd table and then calls `kern_shutdown(fd, SHUT_RDWR)`
   — the exact backend of the unprivileged `shutdown(2)` syscall.
2. Baseline run as nobody: `su -m nobody -c /tmp/panic_trigger`.

## Result (baseline)

- ssh session hung (guest died); `vm.sh status` → `down`.
- Serial console shows the NULL function-pointer call:

```
dmabug: panic: uid=65534 dmabuf fd=3 f_ops=0xffffffff82672180 fo_shutdown=0
dmabug: panic: calling kern_shutdown(3, SHUT_RDWR) ...
Fatal user address access from kernel mode from panic_trigger at 0000000000000000
Fatal trap 12: page fault while in kernel mode
fault virtual address	= 0x0
instruction pointer	= 0x8:0x0
current process		= 1312 (panic_trigger)
db>
```

The kernel printed `fo_shutdown=0` from the live `fp->f_ops` — direct proof
the ops vector member is NULL on a real dma-buf file created by the stock
`dma_buf_export()`. IP=0 = the indirect call target. The firing process was
uid 65534 (nobody).

## Why this is real (source trace)

- sys/sys/file.h:76-89 — `struct fileops` has 8 members; `.fo_shutdown` is
  member 7 and every kernel fileops sets it except `dmabuf_fileops`.
- sys/dev/drm/linux_dma-buf.c:107-115 — `dmabuf_fileops` sets only
  read/write/ioctl/kqfilter/stat/close/seek; `fo_shutdown` stays NULL from
  the C99 designated-initializer zero-fill.
- sys/kern/kern_descrip.c:1522-1535 — `kern_shutdown()` = backend of
  `shutdown(2)`: `holdfp(td, fd, -1)` (any fd, no type check, no privilege
  check) then `error = fo_shutdown(fp, how)` — a blind indirect call.
  (FreeBSD's equivalent checks `fp->f_type != DTYPE_SOCKET`; DragonFly
  removed the check and relies on each fileops returning an error instead.)
- Any unprivileged process holding a dma-buf fd (on real hardware: drm
  render node + `DRM_IOCTL_PRIME_HANDLE_TO_FD`, drm_prime.c:669) triggers it.

## Exploitability

This is a NULL function-pointer call, i.e. control transfer to address 0.
Userland cannot map page 0 on DragonFly (no MAP_FIXED-at-0 path), so the
practical result is a denial of service (kernel panic), not code execution.
Impact: unprivileged local DoS on any machine with a drm device that supports
PRIME export (i915/radeon/amdgpu — the standard desktop configuration).

## Fix validation

`fix.diff` (one line: `.fo_shutdown = badfo_shutdown` in `dmabuf_fileops`),
applied to the guest's /usr/src, drm.ko rebuilt + installed, reboot:

```
dmabug: panic: ... fo_shutdown=0xffffffff8062e5d0 (NULL => indirect call to 0)
dmabug: panic: shutdown RETURNED (fo_shutdown set => fixed)
[panic_trigger] shutdown() returned 0 -- kernel survived
PANIC_RC=0   (guest stayed up)
```

Baseline reproduced the panic (fix_baseline_reproduced=1); patched kernel did
not (fix_patched_reproduced=0). fix_status=fixed.

## Caveat

The QEMU guest has no GPU, so the dma-buf fd was created by the kmod calling
the stock `dma_buf_export()`/`dma_buf_fd()` in the trigger process's context
instead of by a render node ioctl. Everything downstream of fd creation —
`kern_shutdown()` → `fo_shutdown()` — is the genuine unmodified kernel path,
executed with the credentials of uid 65534.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
