Guest debug registers (DR7/DR0-3) persist in host after #VMEXIT enabling host kernel panic via injected HW breakpoint
Summary
AMD SVM does NOT restore host DR7 on #VMEXIT (no host-save-area for DRs). VMRUN loads guest DR7 from VMCB, #VMEXIT leaves it active in hardware. svm_vcpu_guest_dbregs_leave() (:1500) calls x86_curthread_restore_dbregs() which early-returns without clearing DR7 when PCB_DBREGS is unset (common case, nvmm_x86_internal.h:161). Guest sets DR0=kernel_addr + DR7=data_breakpoint (intercept_dr=0 at :2257, no VMEXIT on mov dr). HLT -> VMEXIT -> host runs exit handlers with guest DR7 active -> kernel touches watched addr -> #DB in kernel mode -> trap_fatal() -> panic. VM ISOLATION BREAK. nvmm group only. Same bug in VMX backend. Fix: x86_set_dr7(0) after svm_vmrun and in dbregs_leave.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1315 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source-trace verdict: guest DR7 persists in host context (SVM has no host DR save area) | 3.0 KB | β raw |
| README.md | readme | build/run/expected for this hardware-gated finding | 2.0 KB | β raw |
| trigger_path.c | trigger-source | documents the unreachable trigger path (no SVM on guest CPU) | 1.7 KB | view raw |
| fix.diff | suggested-fix | save host DR7 unconditionally on enter, restore unconditionally on leave | 847 B | view raw |
| build.sh | build-log | no userspace PoC; documents hardware-gated nature | 389 B | view raw |
| run.sh | run-log | reachability check (module/PCI/CPU) | 677 B | view raw |
| env.txt | environment | guest uname, cc, PCI, CPU (no SVM), module presence | 2.2 KB | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1298 / DF-1305 / DF-1314 / DF-1315 β hardware-gated driver findings
These four findings are kernel driver/virtualization bugs that are confirmed real by source trace but that cannot run on the QEMU audit guest because the required hardware is absent (see env.txt):
| Finding | Subsystem | Required hardware | Present on guest? |
|---|---|---|---|
| DF-1298 | amdgpu display VBIOS parser | AMD GPU (amdgpu) | NO (QEMU std-VGA only) |
| DF-1305 | radeon kv DPM | AMD radeon KV APU | NO |
| DF-1314 | radeon btc/evergreen DPM | AMD radeon NI GPU | NO |
| DF-1315 | nvmm AMD-SVM backend | AMD-SVM CPU | NO (guest CPU has no SVM bit) |
Build
./build.sh
There is no userspace PoC binary to compile for these β the vulnerable code
is inside a kernel driver/VMM module that only executes when the relevant device
attaches or the SVM backend runs. build.sh documents this.
Run
./run.sh
run.sh performs a reachability check (kldstat, pciconf, dmesg) and
reports that the path is unreachable on this guest. No panic/leak is expected
here because the trigger hardware is absent.
Expected (bug present, on a host WITH the hardware)
Each VERDICT.md describes the exact trigger and the kernel-level effect (heap overflow / OOB write / host DR7 persistence). On this guest those are latent.
Reproduce the FIX validation
The fix for each is fix.diff. To compile-validate a module fix:
1. scp fix.diff to the guest; cd /usr/src && patch -p1 < fix.diff
2. Build the relevant module, e.g.
cd /usr/src && make -j6 MODULES_OVERRIDE=... or a full
make -j6 nativekernel KERNCONF=X86_64_GENERIC (which also builds modules).
3. Confirm the module/object compiles with no errors (see fix_build.log).
Runtime fix-behaviour cannot be compared on this guest because the PoC paths
are hardware-gated; the fix is therefore classified not_testable with a
compile + source-trace validation.
DF-1315 β AMD-SVM guest debug registers persist in host context (nvmm)
Verdict
NOT TESTABLE AT RUNTIME on this guest β confirmed real latent vulnerability in source.
Mechanism (confirmed by source trace)
sys/dev/virtual/nvmm/x86/nvmm_x86_svm.c is DragonFly's NVMM AMD-SVM backend.
AMD SVM does not save/restore host debug registers across VMRUN/#VMEXIT (there is no host-save-area field for DR0βDR7, unlike Intel VMX's VMCS host state). NVMM relies on software save/restore around the VMRUN:
svm_vcpu_guest_dbregs_enter()(line 1486):- calls
x86_curthread_save_dbregs(cpudata->hstate.drs)β but the DragonFly version (nvmm_x86_internal.h:142) early-returns without saving whenPCB_DBREGSis unset (the common case), so host DR7 is not captured; - then
x86_set_dr7(0)and loads guest DR0βDR3 into hardware. - VMRUN runs the guest. With
intercept_drclear (no DR interception), the guest'sMOV DR7writes go straight to hardware DR7, and a guest can arm a data breakpoint on a host kernel address in DR0 + DR7. svm_vcpu_guest_dbregs_leave()(line 1500):- saves guest DR0βDR3;
- calls
x86_curthread_restore_dbregs(cpudata->hstate.drs)β which again early-returns without touching DR7 whenPCB_DBREGSis unset. So the guest-armed DR7 stays loaded after #VMEXIT, and DR0 still holds the guest's chosen address.
Net effect: a guest under nvmm (AMD-SVM) can leave a hardware data breakpoint
armed on a host address that persists into the host's execution context, so the
next host code touching that address takes an unexpected #DB β host DoS (or
worse, depending on host #DB handling). This is a host/guest isolation break.
Why it does not reproduce on this guest
- The guest CPU reports no AMD-SVM feature:
AMD Features=0x20100800<SYSCALL,NX,LM>β the SVM bit (0x1000) is absent. NVMM's SVM backend will not initialise (no usable SVM), so the VMRUN path cannot be exercised, even ifnvmm.kowere loaded (it is not in GENERIC and not loaded). nvmmis apseudo-devicelisted only inLINT64, not inX86_64_GENERIC.
Severity / realistic ceiling
On an AMD host with SVM, with nvmm available and a VM run by a user able to
open /dev/nvmm, a malicious guest can poison the host's debug registers and
induce host-side #DB faults β a host DoS / isolation break (the finding's
CVSS reflects AV:L/AC:L/PR:L/S:C/A:H). Requires SVM hardware + nvmm access
(often root-only to load the module / create a VM).
Fix (see fix.diff)
- In
svm_vcpu_guest_dbregs_enter: unconditionally save the host DR7 intocpudata->hstate.drs[DR7]before clearing it (so it is available to restore on exit regardless ofPCB_DBREGS). - In
svm_vcpu_guest_dbregs_leave: unconditionally restore that host DR7 after the PCB-gated restore, so a guest-armed breakpoint cannot persist. This mirrors how the misc/FPU state is already handled. Compile-validated (nvmm module build); runtime not exercisable (no SVM on guest).
Fix verification
not_testablecompile+boot validated -Werror
nativekernel rc=0, boots #1 clean
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. NVMM SVM guest DR7 persists past #VMEXIT -> host #DB isolation break. No SVM on guest CPU. nvmm not in GENERIC.
No comments yet.