⬢ DragonFlyBSD Kernel Audit
DF-5673 / rig-flip.txt
← back to finding ↓ download raw
Guest: DragonFly dfbsd 6.5-DEVELOPMENT X86_64_GENERIC x86_64 (QEMU/KVM rig, 6 vCPU)
Baseline kernel: #0 Thu Jul  2 06:02:54 UTC 2026 (stock DEV ISO)
Patched kernel:  #1 Fri Oct  9 19:21:17 UTC 2026 (fix.diff applied)

RIG ANOMALY — CPL3 port I/O at IOPL=0 intermittently permitted by the rig
=========================================================================

The guest kernel never changes TR after boot: the private-TSS/ltr path in
sys/platform/pc64/x86_64/swtch.s:482-512 is dead (#if 0 /* JG */), the TSS
descriptor limit is sizeof(struct x86_64tss)-1 (machdep.c:1698) and
common_tss.tss_iobase = sizeof(struct x86_64tss) (machdep.c:2881) — the
architectural "no IO-permission bitmap, deny all CPL3 I/O" arrangement.
A #GP from CPL3 port access is delivered as SIGBUS (trap.c:512-515).

Observed enforcement of `inb $0x80` at CPL3 / IOPL=0 across this audit:

  boot 1 (stock kernel, pre-fix):
    maxx, no handler, 4 ports x1 + 2x12 loop : 24/24 FAULT
    root, lifecycle RUN A step0             : 1x OK (one-off)
    root, lifecycle RUN B step0             : FAULT
    root, ctrl 12x                          : 12/12 FAULT
    maxx, ctrl 12x                          : 12/12 FAULT
  boot 2 (patched kernel, first boot):
    maxx ctrl 20x : 20/20 OK
    root  ctrl 20x: 20/20 OK   (80/80 OK total incl. PoC steps)
  boot 3 (same patched kernel, after reboot):
    maxx ctrl 20x        : 20/20 FAULT
    root m1 (handler on) : OK x2, maxx m1: FAULT  (suggested uid link)
    same shell seconds later:
      root m1: FAULT, maxx m1: OK, root m1: FAULT, maxx m1: FAULT,
      maxx m1: OK, root m1: FAULT  -> flips within seconds, uid-uncorrelated

Conclusion: in this rig the virtual CPU's IO-bitmap/IOPL enforcement is
flaky per vCPU/moment (KVM artifact; 6 vCPUs, scheduler-dependent). All
"port access OK/FAULT" lines in the PoC logs are corroboration only. The
decisive kernel-state observable is the RFLAGS IOPL field via pushfq:

  baseline chain : child IOPL=3 after fork+close+setuid  (3/3 runs)
  patched chain  : child IOPL=0                           (2 boots)