METEORSSIGNAL stores curproc without reference causing UAF via fork+child-exit+DMA interrupt
Summary
METEORSSIGNAL at cxm.c:2760: sc->enc_proc=curproc with NO PHOLD. Consumed asynchronously from interrupt: ksignal(sc->enc_proc,sc->enc_signal) at :1363-1364 -> phold() -> atomic_add_int(&p->p_lock,1). Only cleared in cxm_close (:2197). fork: child registers via METEORSSIGNAL, child exits, parent keeps fd open -> cxm_close NOT called -> stale struct proc -> next DMA interrupt calls ksignal on freed slab -> UAF write. /dev/cxm0 mode 0444 (unprivileged). Trigger: fork, child METEORSSIGNAL+METEORCAPTUR+exit, parent read() loop. Fix: store pid_t, use pfind()+PRELE() at delivery.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1295 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | readme | finding summary + UAF trigger | 3.1 KB | β raw |
| VERDICT.md | verdict | mechanism + citations + fix | 2.3 KB | β raw |
| fix.diff | suggested-fix | PHOLD curproc when storing enc_proc; PRELE on clear in ioctl and cxm_close | 645 B | view raw |
| build.sh | build-script | no PoC binary | 357 B | view raw |
| run.sh | run-script | no runtime PoC (cxm absent) | 333 B | view raw |
| env.txt | environment | guest PCI/kld/uname | 862 B | 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-1295 β cxm METEORSSIGNAL stores curproc without PHOLD β UAF
Finding
cxm_ioctl (METEORSSIGNAL) at sys/dev/video/cxm/cxm.c:2760 stores
curproc into sc->enc_proc with no PHOLD:
sc->enc_proc = sig ? curproc : NULL;
The stored pointer is consumed asynchronously from the encoder-DMA interrupt
at cxm.c:1363-1364:
if (sc->enc_proc)
ksignal(sc->enc_proc, sc->enc_signal);
ksignal β lwpsignal (sys/kern/kern_sig.c:1150) does PHOLD(p) which
increments p->p_lock β a write into the proc struct.
sc->enc_proc is cleared only in cxm_close (cxm.c:2197). The
exploitation pattern: a child process registers via METEORSSIGNAL then
exits while the parent keeps the device fd open. cxm_close is not
called for the child (the fd is still open in the parent), so sc->enc_proc
retains a pointer to the child's now-freed struct proc. The next DMA
interrupt calls ksignal on the freed slab β UAF write.
Why we did not reproduce at runtime
The cxm driver attaches only to Conexant CX23416/CX2388x PCI video capture
cards. The audit guest has no such device. The driver is built as a module
(not in X86_64_GENERIC, not loaded β kldstat shows no cxm). Without the
device, /dev/cxm0 does not exist and METEORSSIGNAL is unreachable.
The brief claims /dev/cxm0 is mode 0444 β that is the default cdev mode
for cxm; with the card present, an unprivileged user can open() (read-only
satisfies the permission check) and issue METEORSSIGNAL via ioctl. The
trigger is therefore plausibly unprivileged when the card is present.
Source-level confirmation
cxm.c:2760βsc->enc_proc = sig ? curproc : NULL;β no PHOLD.cxm.c:2761βsc->enc_signal = sig;cxm.c:1363-1364βif (sc->enc_proc) ksignal(sc->enc_proc, sc->enc_signal);β async consumer.kern_sig.c:1118-1121βksignal(p, sig) { lwpsignal(p, NULL, sig); }.kern_sig.c:1150βPHOLD(p);insidelwpsignalβ write top->p_lock.cxm.c:2197βsc->enc_proc = NULL;only oncxm_close.cxm.h:235βstruct proc *enc_proc;β raw pointer, no refcount.
The bug is the missing PHOLD/PRELE (or pid_t + pfind) lifecycle.
Confirmed real.
Realistic impact ceiling
UAF write (atomic increment of p_lock) on a freed struct proc slab.
Could be groomed into a more useful primitive on a non-debug kernel; on
default GENERIC (INVARIANTS ON) the slab poisoning (WEIRD_ADDR 0xdeadc0de)
would catch the deref of a freed proc and panic before exploitation lands.
Preconditions: cxm card present + admin-chowned /dev/cxm0 (or default 0444
sufficient for read-only open) + fork/exit dance. Plausibly unprivileged
local β kernel memory corruption when the HW is present.
Fix
fix.diff adds a PHOLD(curproc) when storing and PRELE(sc->enc_proc)
when clearing in both cxm_ioctl(METEORSSIGNAL) and cxm_close. This pins
the proc struct until the driver is done with it, eliminating the UAF. The
alternative (pid_t + pfind/PRELE at delivery) is more invasive; the
PHOLD/PRELE pair is the minimal correct fix and matches the pattern used by
sigio in kern/kern_sig.c.
DF-1295 β cxm METEORSSIGNAL stores curproc without PHOLD β UAF
Verdict
NOT REPRODUCED β real source-level bug confirmed; unreachable on this guest (no Conexant video capture card; cxm module not loaded).
Mechanism (verified)
cxm.c:2760βsc->enc_proc = sig ? curproc : NULL;β stores rawstruct proc *with no PHOLD.cxm.c:1363-1364βif (sc->enc_proc) ksignal(sc->enc_proc, sc->enc_signal);β async consumer from encoder-DMA interrupt.kern_sig.c:1118-1120βksignalβlwpsignal.kern_sig.c:1150βPHOLD(p);insidelwpsignalβatomic_add_int(&p->p_lock, 1)β write into the proc slab.cxm.c:2197βsc->enc_proc = NULL;only incxm_close.cxm.h:235βstruct proc *enc_proc;raw pointer, no refcount.
Trigger (when HW present): child registers via METEORSSIGNAL, child exits,
parent keeps fd open β cxm_close not called for the child β sc->enc_proc
retains stale pointer β next DMA interrupt β ksignal on freed slab β UAF
write.
Confirmed real. The missing PHOLD/PRELE is the lifecycle defect.
Why not triggered on this guest
pciconf -l(env.txt): no Conexant capture device. Only virtio + Intel PIIX3/PIIX4.kldstat -v | grep cxm: empty β module not loaded.cxmis not in X86_64_GENERIC (it is a loadable module:sys/dev/video/cxm/Makefile).
Phase 4(d): genuinely not reachable on this kernel. With the card present the
trigger is plausibly unprivileged (/dev/cxm0 default mode 0444 β read-only
open succeeds β ioctl(METEORSSIGNAL) permitted).
Fix
fix.diff:
1. cxm_ioctl(METEORSSIGNAL): PRELE the previous enc_proc if being replaced; PHOLD(curproc) when storing.
2. cxm_close: PRELE(sc->enc_proc) before clearing.
This pins the proc until the driver releases it, closing the UAF. Both
PHOLD/PRELE macros (sys/sys/proc.h:482-483) are already in scope via the
cxm.c includes.
Fix validation
Compiles cleanly in the unified 5-fix kernel build (fix_build.log).
Runtime before/after is not_testable β no cxm device.
Realistic impact
UAF write (atomic inc of p_lock) on a freed struct proc slab, gated on
cxm HW being present + a fork/exit dance. Likely panic on default GENERIC
(INVARIANTS); potentially groomable on a non-debug kernel.
Fix verification
not_testablecompile validated
nativekernel rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. cxm METEORSSIGNAL stores curproc without PHOLD -> ksignal on freed proc slab UAF. cxm module, no Conexant HW.
No comments yet.