# DF-5657 — pc64 set_dbregs() stores DR7 with reserved bits 63:32 unvalidated → ring-0 #GP inside cpu_heavy_restore on context switch → fatal kernel trap (panic) from an unprivileged ptrace() of the attacker's own child

File under audit (owner file): `sys/platform/pc64/x86_64/procfs_machdep.c` (procfs_write_dbregs → set_dbregs plumbing)
Root cause: `sys/platform/pc64/x86_64/machdep.c` set_dbregs() + `sys/platform/pc64/x86_64/swtch.s` cpu_heavy_restore()

## TL;DR

An unprivileged user (uid 1001) calls `ptrace(PT_SETDBREGS)` on its own stopped
child with `dbregs.dr[7] = 0xdeadbeef00000000`. `set_dbregs()` validates only
the R/W fields (bits 16–29) and the dr0–dr3 addresses vs `VM_MAX_USER_ADDRESS`;
it stores the raw 64-bit dr7 into `pcb->pcb_dr7` and sets `PCB_DBREGS`
(machdep.c:3215-3222). On the next context switch into the tracee,
`cpu_heavy_restore()` reloads %dr7 masking ONLY bits 10–15
(`andq $~0x0000fc00`), so the reserved bits 63:32 flow straight into
`movq %rax,%dr7` (swtch.s:597-617). On Intel CPUs — and unconditionally under
KVM, where the host `kvm_set_dr()` injects #GP for any set bit in DR7[63:32] —
this raises a ring-0 #GP in the middle of a context switch. The fault is not at
`doreti_iret`, so trap.c's kernel-mode T_PROTFLT redirect does not apply; the
trap falls through to `trap_fatal()` (trap.c:770) → fatal trap, all CPUs
stopped, system down.

Reproduced on the stock guest kernel; fix (reject dr7 with bits 63:32 set in
set_dbregs) validated on a rebuilt kernel: same PoC now gets EINVAL, guest
stays up, legitimate dr7 values (0, 0x401) still accepted.

## Reproduce

Guest: `dfbsd-qemu/vm.sh up` (QEMU/KVM), then as unprivileged user (maxx):

```
./build.sh          # cc -O -o /tmp/poc poc.c
./run.sh            # baseline (dr7=0) then attack (dr7=0xdeadbeef00000000)
```

Expected (stock kernel):
- baseline: `PT_SETDBREGS(dr7=0) ACCEPTED`, child resumes, guest stays up;
- attack:   `PT_SETDBREGS(dr7=0xdeadbeef00000000) ACCEPTED`, then on
  PT_CONTINUE the kernel panics — serial console shows:
  `Fatal trap 9: general protection fault while in kernel mode` …
  `Stopped at cpu_heavy_restore+0x1ab: movl %eax,%dr7` (see panic.txt);
  ssh dies; `vm.sh status` → down.

On the fix-patched kernel: attack run prints `PT_SETDBREGS: Invalid argument`,
guest stays up (see fix_run.log).

## Impact

Unprivileged local kernel panic / DoS (deterministic under KVM and on Intel
bare metal; AMD bare metal ignores writes to DR7[63:32] and is not affected by
this particular variant). No memory-corruption primitive: the fault is a clean
#GP(0) taken to ddb — the ddb prompt is console-only and not reachable from an
ssh session, so the ceiling is denial of service.
