β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1215

METEORSVIDEO ioctl allows unprivileged user to set arbitrary physical DMA target address

Summary

METEORSVIDEO ioctl at bktr_core.c:1396-1402 stores user-supplied video->addr (32-bit physical address) into bktr->video with ZERO priv check and ZERO address validation. Every RISC DMA builder (rgb_vbi_prog:2670, rgb_prog:2840, yuvpack_prog:2995, yuv422_prog:3113, yuv12_prog:3214) uses it as bt848 bus-master DMA write target. Device nodes created mode 0444 (world-readable) at bktr_os.c:325, ioctls not gated by open mode. Any unprivileged user: open /dev/bktr0 O_RDONLY -> METEORSVIDEO addr=phys -> METEORCAPTUR continuous -> bt848 writes video frames to arbitrary physical memory. No suser/priv_check/caps_priv_check anywhere in bktr_core.c. Arbitrary physical-memory write primitive -> reliable root escalation. Fix: caps_priv_check_td(td, SYSCAP_RESTRICTEDROOT) when addr!=0.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1215 Β· 26 files
FileTypeDescriptionSize
poc_rig.c trigger-source decisive PoC: unpriv METEORSVIDEO via production video_ioctl (rig) 2.0 KB view raw
bktrig.c trigger-source KLD rig dispatching to production video_ioctl from bktr.ko 3.5 KB view raw
bktrig_nodep.c trigger-source nodep rig variant for the fix-built kernel 3.5 KB view raw
poc_physdma.c trigger-source original hardware trigger PoC (real bt848 only) 1.4 KB view raw
Makefile.kld build-script rig module Makefile (bsd.kmod.mk) 256 B ↓ download
rig_setup.sh build-script exact guest rig setup (build+load, root) 1.9 KB view raw
build.sh build-script userland PoC build 154 B view raw
run.sh run-script decisive unprivileged run 162 B view raw
build.log build-log combined decisive build record 1.7 KB view raw
run.log run-log combined decisive baseline run (ENOENT + rig attack accepted) 1.5 KB view raw
baseline_run.log run-log original PoC: /dev/bktr0 ENOENT (no bt848 PCI) 261 B view raw
rig_build.log build-log rig module compile/link (U video_ioctl) 4.4 KB view raw
rig_load.log run-log rig load; production bktr.ko auto-loaded; video_ioctl=0xffffffff82606190 431 B view raw
baseline_rig_run.log run-log BASELINE ATTACK: uid=1001 METEORSVIDEO rc=0, readback 0x100000 278 B view raw
fix.diff suggested-fix caps_priv_check_td gate on METEORSVIDEO when addr!=0 1.1 KB view raw
fix_build.log build-log FULL nativekernel DF1215FIX build (rc=0, 315s) 5.6 MB ↓ download
fix_install.log build-log installkernel into /boot/kernel 80.4 KB view raw
fixed_rig_load.log run-log rig on DF1215FIX (video_ioctl kernel global, fixed) 314 B view raw
fixed_rig_run.log run-log FIXED: uid=1001 gets EPERM; addr=0 path intact 267 B view raw
fixed_root_run.log run-log root contrast on fixed kernel: redirect still allowed 530 B view raw
dmesg_fixed.txt environment fixed-kernel dmesg (boot-stable) 13.6 KB view raw
kldstat_fixed.txt environment kldstat -v on fixed kernel 5.6 KB view raw
env.txt environment guest env: unames, PCI inventory, module state, symbols 2.1 KB view raw
fix_build_pass1.log build-log pass-1 combined fix build (superseded by behavioral A/B) 5.6 MB ↓ download
VERDICT.md verdict full narrative verdict 4.6 KB ↓ raw
verdict.json verdict machine verdict (persist_poc/persist_fix input) 5.8 KB view raw
VERDICT.md verdict full narrative verdict
↓ download raw

DF-1215 VERDICT -- inconclusive (impact: none; confidence: certain)

Bottom line

Authorization bypass REPRODUCED with unmodified production code: a KLD rig (/dev/bktrig0 -> production video_ioctl() from the stock unfixed /boot/kernel/bktr.ko, synthetic post-attach softc) let uid=1001 METEORSVIDEO an arbitrary physical DMA target (addr=0x100000 -> rc=0, METEORGVIDEO readback 0x100000) -- the exact field every bt848 RISC DMA builder consumes (bktr_core.c:2670/2841/2996/3114/3215) -- with no privilege check anywhere in the driver (nodes 0444, bktr_os.c:325). The corruption SINK (bt848 bus-master DMA write) cannot fire on this guest: QEMU has no Brooktree PCI device (pciconf: none; /dev/bktr0 ENOENT, re-verified), so no panic/uid0 is demonstrable here -- hence inconclusive rather than reproduced, and not not_reproduced (nothing failed; the bypass half did reproduce). On real bt848 hardware the stored target makes METEORCAPTUR DMA attacker-deterministic bytes to arbitrary physical memory -> ucred/function-pointer overwrite -> uid=0 (no SMAP/SMEP/KASLR). Fix VALIDATED behaviorally this run: DF1215FIX kernel (GENERIC+device bktr+fix.diff, nativekernel rc=0 315s) -> identical rig+user gets EPERM for addr!=0, addr=0 path intact, root retains redirect.

Reproduce

build: guest: (maxx) cc -O2 -Wall -o poc_physdma poc_physdma.c; cc -O2 -Wall -o poc_rig poc_rig.c; (root /root/bktrig[/nodep]) make -m /usr/src/share/mk SYSDIR=/usr/src/sys -- see rig_setup.sh / build.sh
run:   guest: (root once) kldload /root/bktrig/bktrig.ko; (maxx) ./poc_rig -- see run.sh

Evidence in this pack

run.log (combined decisive run); baseline_rig_run.log (THE ATTACK: uid=1001 METEORSVIDEO addr=0x100000 rc=0, readback 0x100000); rig_load.log (production bktr.ko loaded, video_ioctl=0xffffffff82606190); baseline_run.log (/dev/bktr0 ENOENT, no bt848 PCI); fixed_rig_run.log (EPERM on fixed kernel); fixed_root_run.log (root retains redirect); fix_build.log/fix_install.log (DF1215FIX rc=0); VERDICT.md for the full narrative

Kernel references

Exploit chain

On real bt848 hardware: open /dev/bktr0 O_RDONLY (mode 0444, any user) -> ioctl METEORSVIDEO addr= (no auth, bktr_core.c:1396) -> ioctl BT848_SCBARS for deterministic payload bytes -> ioctl METEORCAPTUR METEOR_CAP_CONTINOUS (no auth, bktr_core.c:1502) -> bt848 bus-master writes frame bytes to arbitrary phys -> overwrite struct ucred cr_uid or function pointer -> uid=0. NOT exercisable on this guest: chain blocked at the DMA engine (no bt848 PCI emulation); only the METEORSVIDEO acceptance half was rig-reproduced.

Fix validation (A/B)

Gate METEORSVIDEO redirect on caps_priv_check_td(td, SYSCAP_RESTRICTEDROOT) when video->addr != 0 (fix.diff; behaviorally validated); additionally consider 0600 device nodes and an auth check on METEORCAPTUR.

Baseline vs post-fix behavior is in run.log / run_fixed*.log (userspace) or panic.txt/hang.txt vs run_fixed_kernel.log (kernel); the identical rig ran both sides.

poc_changes

poc_physdma.c unchanged. Added poc_rig.c + KLD rig (bktrig.c / bktrig_nodep.c): production video_ioctl is a global symbol so the rig dispatches /dev/bktrig0 ioctls to it on a synthetic zeroed bktr_softc (bigbuf!=0 = post-attach state); fixed include path (dev/video/bktr/ioctl_bt848.h), added (struct dev_ops lives there in this tree), kld build via bsd.kmod.mk + device_if.h/bus_if.h copied from /usr/obj kernel dir, kldload by full path; nodep variant (MODULE_DEPEND sed'ed out) for the fix kernel where bktr is compiled in; fixed seeded bzero(&g,0xAA) length/pattern swap -> memset(&g,0xAA,sizeof(g)).

Guest: 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 Attempts: 6 Runtime: ~1380s

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.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

DF1215FIX kernel (X86_64_GENERIC + device bktr + fix.diff; nativekernel rc=0 in 315s, -Werror clean; installkernel rc=0; boot-stable, kern.version #0 Sun Oct 11 21:52:44 UTC 2026). Identical rig + identical uid=1001 attack: METEORSVIDEO addr=0x100000 -> EPERM (baseline: rc=0 acceptance via unfixed production bktr.ko), METEORGVIDEO readback 0x0, addr=0 kernel-buffer mode still rc=0, root retains redirect (rc=0, readback 0x100000). Bad behavior GONE, legitimate use preserved.

fix_run.log (combined A/B); fixed_rig_run.log (EPERM); fixed_root_run.log (root contrast); fix_build.log (full nativekernel log, rc=0); fix_install.log; fixed_rig_load.log (video_ioctl kernel global 0xffffffff80830790 on DF1215FIX); patched-source gate at sys/dev/video/bktr/bktr_core.c:1409
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Sun Oct 11 21:52:44 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/DF1215FIX x86_64

Confirmed kernel references

Detail

Exploit chain

On real bt848 hardware: open /dev/bktr0 O_RDONLY (mode 0444, any user) -> ioctl METEORSVIDEO addr= (no auth, bktr_core.c:1396) -> ioctl BT848_SCBARS for deterministic payload bytes -> ioctl METEORCAPTUR METEOR_CAP_CONTINOUS (no auth, bktr_core.c:1502) -> bt848 bus-master writes frame bytes to arbitrary phys -> overwrite struct ucred cr_uid or function pointer -> uid=0. NOT exercisable on this guest: chain blocked at the DMA engine (no bt848 PCI emulation); only the METEORSVIDEO acceptance half was rig-reproduced.

Evidence (decisive lines)

run.log (combined decisive run); baseline_rig_run.log (THE ATTACK: uid=1001 METEORSVIDEO addr=0x100000 rc=0, readback 0x100000); rig_load.log (production bktr.ko loaded, video_ioctl=0xffffffff82606190); baseline_run.log (/dev/bktr0 ENOENT, no bt848 PCI); fixed_rig_run.log (EPERM on fixed kernel); fixed_root_run.log (root retains redirect); fix_build.log/fix_install.log (DF1215FIX rc=0); VERDICT.md for the full narrative

PoC changes

poc_physdma.c unchanged. Added poc_rig.c + KLD rig (bktrig.c / bktrig_nodep.c): production video_ioctl is a global symbol so the rig dispatches /dev/bktrig0 ioctls to it on a synthetic zeroed bktr_softc (bigbuf!=0 = post-attach state); fixed include path (dev/video/bktr/ioctl_bt848.h), added (struct dev_ops lives there in this tree), kld build via bsd.kmod.mk + device_if.h/bus_if.h copied from /usr/obj kernel dir, kldload by full path; nodep variant (MODULE_DEPEND sed'ed out) for the fix kernel where bktr is compiled in; fixed seeded bzero(&g,0xAA) length/pattern swap -> memset(&g,0xAA,sizeof(g)).

Verified recommended fix

Gate METEORSVIDEO redirect on caps_priv_check_td(td, SYSCAP_RESTRICTEDROOT) when video->addr != 0 (fix.diff; behaviorally validated); additionally consider 0600 device nodes and an auth check on METEORCAPTUR.

Verdict

Authorization bypass REPRODUCED with unmodified production code: a KLD rig (/dev/bktrig0 -> production video_ioctl() from the stock unfixed /boot/kernel/bktr.ko, synthetic post-attach softc) let uid=1001 METEORSVIDEO an arbitrary physical DMA target (addr=0x100000 -> rc=0, METEORGVIDEO readback 0x100000) -- the exact field every bt848 RISC DMA builder consumes (bktr_core.c:2670/2841/2996/3114/3215) -- with no privilege check anywhere in the driver (nodes 0444, bktr_os.c:325). The corruption SINK (bt848 bus-master DMA write) cannot fire on this guest: QEMU has no Brooktree PCI device (pciconf: none; /dev/bktr0 ENOENT, re-verified), so no panic/uid0 is demonstrable here -- hence inconclusive rather than reproduced, and not not_reproduced (nothing failed; the bypass half did reproduce). On real bt848 hardware the stored target makes METEORCAPTUR DMA attacker-deterministic bytes to arbitrary physical memory -> ucred/function-pointer overwrite -> uid=0 (no SMAP/SMEP/KASLR). Fix VALIDATED behaviorally this run: DF1215FIX kernel (GENERIC+device bktr+fix.diff, nativekernel rc=0 315s) -> identical rig+user gets EPERM for addr!=0, addr=0 path intact, root retains redirect.