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

IPC_STAT (and dead SEM_STAT) copy out live kernel heap pointer sem_base to unprivileged users

Field Value
ID DF-2783
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
CWE CWE-200 kernel heap-address disclosure
File sys/kern/sysv_sem.c
Lines 431, 450 (field sem.h:36)
Area kern
Confidence certain
Discovered 2026-08-31
Pass 2 (GLM 5.3 second pass)
Bucket kernleak
Reported pending
Known CVE none
CVE match novel

Summary

sys___semctl() copies the in-kernel semid_ds verbatim for IPC_STAT (and the dead-code SEM_STAT). struct semid_ds.sem_base is a live kernel pointer to the M_SEM allocation backing the set. Any unprivileged user reads it via their own semget(IPC_PRIVATE)+IPC_STAT: reproduced sem_base=0xfffff8008d363168 to uid 1001, deterministic within an allocation sequence. SEM_STAT is dead code on DragonFly (pre-switch seq validation vs in-case index check mutually exclusive) but shares the copyout. The sibling sysv_msg.c IPC_STAT (msg_first/msg_last) has the same pattern β€” noted for that file's owner.

Proof of contest

VERIFIED (findings/poc/DF-2783/ipcstat_leak.c): unpriv Γ—3 runs β†’ identical pointer; fixed kernel β†’ NULL + clean. Fix (copy to the existing stack sbuf, NULL sem_base, copyout the sanitized copy at both sites) validated in-guest.

See findings/poc/DF-2783/fix.diff.

Timeline

  • 2026-08-31 Discovered during pass-2 audit of sysv_sem.c (GLM 5.3); unpriv leak reproduced + fix validated same run.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2783 Β· 10 files
FileTypeDescriptionSize
ipcstat_leak.c β€” 1.9 KB view raw
build.sh β€” 61 B view raw
run.sh β€” 145 B view raw
build.log β€” 9 B view raw
run.log β€” 609 B view raw
leak_sample.txt β€” 171 B view raw
env.txt β€” 305 B view raw
fix.diff β€” 770 B view raw
VERDICT.md β€” 1.8 KB ↓ raw
verdict.json β€” 2.4 KB view raw
VERDICT.md
↓ download raw

DF-2783 VERDICT

Status: reproduced (leak, certain). Fix validated (fixed).

Baseline (stock kernel #0, Thu Jul 2 06:02:54 UTC 2026)

Unprivileged uid 1001, own semget(IPC_PRIVATE, 3, 0600) + IPC_STAT:

IPC_STAT : sem_base=0xfffff8008d363168 nsems=3 mode=1600   (run 1)
IPC_STAT : sem_base=0xfffff8008d363168 nsems=3 mode=1600   (run 2)
IPC_STAT : sem_base=0xfffff8008d363168 nsems=3 mode=1600   (run 3)
LEAK: kernel pointer disclosed to uid=1001  (rc=0)

0xfffff800_8d363168 is a live kernel-map heap address β€” the M_SEM allocation returned by kmalloc() at sysv_sem.c:698 and stored in semaptr->ds.sem_base β€” copied verbatim by copyout(&semaptr->ds, …) at sys/kern/sysv_sem.c:431 (IPC_STAT) and :450 (SEM_STAT). Pointer is deterministic within a boot/alloc-sequence window (three identical values) and drifts with heap churn (see leak_sample.txt: 0xfffff8008d981fe8 … across later runs) β€” always a non-NULL kernel address. Leak class: kernel heap-address disclosure β†’ KASLR-relevant; on this INVARIANTS guest KASLR is off, but the disclosure is configuration-independent.

PoC changes vs seed

None (finding + PoC authored in this run). SEM_STAT probe initially passed the IPC id; the kernel's pre-switch seq check (sysv_sem.c:376-380) plus in-case index check (:441) make SEM_STAT unconditionally EINVAL (dead command β€” noted in README); leak stands on IPC_STAT alone.

Fix validation (patched kernel #1, built in-guest from fix.diff)

IPC_STAT : sem_base=0x0 nsems=3 mode=1600
clean: kernel pointer zeroed to uid=1001  (rc=2)

Bad behavior gone: pointer is NULL; command still succeeds otherwise.

Impact ceiling

Low β€” single-pointer kernel-heap disclosure to any IPC_R holder (any user, own semaphore). No memory corruption; defeats kernel address randomization and aids heap-layout inference for other bugs.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Patched kernel (fix.diff applied in-guest, nativekernel build RC=0, installkernel RC=0) prints sem_base=0x0 / 'clean' rc=2; leak gone, IPC_STAT otherwise functional.

["run.fixed.log: 'IPC_STAT : sem_base=0x0 nsems=3 mode=1600' + 'clean: kernel pointer zeroed to uid=1001'", 'fix.diff']
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #1: Tue Sep 1 06:03:53 UTC 2026 root:dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Confirmed kernel references

Detail

Evidence (decisive lines)

["run.log: 'IPC_STAT : sem_base=0xfffff8008d363168' x3 + 'LEAK: kernel pointer disclosed to uid=1001'", 'leak_sample.txt: 3 further kernel-address samples', 'VERDICT.md: baseline vs patched comparison']

PoC changes

SEM_STAT probe changed from IPC id to array index, then to informational: kernel's pre-switch seq check (376-380) plus in-case index check (441) make SEM_STAT unconditionally EINVAL (dead command, noted); leak proven via IPC_STAT alone.

Verified recommended fix

Copy semid_ds to stack, NULL sem_base before copyout in IPC_STAT and SEM_STAT (validated: pointer prints 0x0, rc=2).

Verdict

sys___semctl IPC_STAT (sysv_sem.c:431) copyout of the live semid_ds discloses the kernel heap pointer sem_base (M_SEM allocation) to any unprivileged user with IPC_R access (own semget). Reproduced on stock kernel: sem_base=0xfffff8008d363168 identical across 3 runs, uid 1001. SEM_STAT (:450) has the same code but is dead (pre-switch seq check :376-380 vs in-case index check :441 are mutually exclusive).