sys_getpgid / sys_getsid lack cross-session visibility checks (unprivileged pgid/sid enumeration)
| Field | Value |
|---|---|
| ID | DF-0037 |
| Status | new |
| Severity | Info |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N |
| CWE | CWE-862 Missing Authorization |
| File | sys/kern/kern_prot.c |
| Lines | 106-131 (getpgid), 136-158 (getsid) |
| Area | kern |
| Confidence | likely |
| Discovered | 2026-06-29 |
| Reported | pending |
Summary
sys_getpgid and sys_getsid look up an arbitrary target pid via pfind()
and return its process-group-id / session-id without verifying that the caller
may inspect that process. POSIX.1-2017 specifies EPERM when the target is not
in the caller's session. Any local user can thus enumerate the pgid and
session-id of every process on the system (including those in other sessions
and UIDs).
Root cause
/* sys_getpgid :119-126 */
pt = pfind(uap->pid);
...
lwkt_gettoken_shared(&pt->p_token);
sysmsg->sysmsg_result = pt->p_pgrp->pg_id; /* no p_trespass / PRISON_CHECK */
lwkt_reltoken(&pt->p_token);
/* sys_getsid :149-154 */
pt = pfind(uap->pid);
...
sysmsg->sysmsg_result = pt->p_session->s_sid; /* no visibility check */
Contrast sysctl kern.proc (kern_proc.c:1690,1768) which calls
PRISON_CHECK before revealing process metadata.
Threat model & preconditions
- Attacker position: any local unprivileged user.
- Privileges gained or impact: information disclosure β O(process-count)
bits per call (the pgid/session-id of every process, including other
sessions/UIDs). Session/pgid-leader fingerprinting; same class as historical
BSD
get*sidinfo-leak CVEs. Not an escalation primitive. - Required config or capabilities: none; default kernel.
- Reachability:
getpgid(2)/getsid(2)with an arbitrary pid.
Proof of concept
PoC source: findings/poc/DF-0037/leak_pgid.c
Build & run (unprivileged)
cc -o leak_pgid findings/poc/DF-0037/leak_pgid.c ./leak_pgid
Expected output
The pgid/sid of every process on the system, with no EPERM for
out-of-session targets.
Impact
Low-grade information disclosure / POSIX non-compliance. Rated Info (same class as DF-0015/DF-0025).
Recommended fix
Apply a p_trespass/session check before returning (mirroring kern.proc's
PRISON_CHECK):
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -123,6 +123,11 @@
if (error == 0) {
lwkt_gettoken_shared(&pt->p_token);
+ if (pt->p_session != p->p_session &&
+ caps_priv_check(p->p_ucred, SYSCAP_NOPROC_TRESPASS)) {
+ error = EPERM;
+ } else {
sysmsg->sysmsg_result = pt->p_pgrp->pg_id;
+ }
lwkt_reltoken(&pt->p_token);
}
(and the analogous check in sys_getsid at :153-154.)
References
sys/kern/kern_prot.c:106-131,136-158βgetpgid/getsid(no visibility check).sys/kern/kern_proc.c:1690,1768βkern.procappliesPRISON_CHECK.- CWE-862 Missing Authorization.
Timeline
- 2026-06-29 Discovered during automated file-by-file audit of
sys/kern/kern_prot.c. - pending Reported to DragonFlyBSD security contact.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0037 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| leak_pgid.c | trigger-source | system-wide pgid/sid enumeration PoC | 890 B | view raw |
| leak_xsess.c | trigger-source | definitive parent/setsid-child cross-session probe (added by runner) | 2.3 KB | view raw |
| build.sh | build-script | cc -o leak_pgid leak_pgid.c; cc -o leak_xsess leak_xsess.c | 157 B | view raw |
| run.sh | run-script | unprivileged run of both PoCs | 627 B | view raw |
| run.log | run-log | baseline #0 decisive run: 22 procs enumerated, errno=0 cross-session | 1.2 KB | view raw |
| fix_run.log | run-log | patched #1 decisive run: EPERM, 3 procs (own session only) | 574 B | view raw |
| fix_build_tail.txt | build-log | nativekernel build log tail, NK_DONE rc=0 | 4.6 KB | view raw |
| fix.diff | suggested-fix | adds pt->p_session != p->p_session && SYSCAP_NOPROC_TRESPASS check to both syscalls | 856 B | view raw |
| env.txt | environment | uname, cc version, kern.version | 295 B | view raw |
| VERDICT.md | verdict | full narrative: mechanism, proof, fix, validation | 4.2 KB | β raw |
| README.md | readme | PoC overview | 725 B | β 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-0037 β PoC
leak_pgid.c β unprivileged enumeration of every process's pgid/session-id
via getpgid/getsid (no cross-session EPERM).
The bug
sys_getpgid (kern_prot.c:106-131) and sys_getsid (:136-158) call
pfind(arbitrary pid) and return pt->p_pgrp->pg_id / pt->p_session->s_sid
with no p_trespass/PRISON_CHECK/session-equality check. POSIX mandates
EPERM for out-of-session targets; DragonFly returns the value to any caller.
Build & run (unprivileged)
cc -o leak_pgid findings/poc/DF-0037/leak_pgid.c ./leak_pgid
Expected output (bug present)
pid 1 pgid 1 sid 1 pid <sshd> ... ... N processes' pgid/sid enumerated as uid=1000 (no EPERM)
DF-0037 β sys_getpgid / sys_getsid cross-session info leak
| Field | Value |
|---|---|
| Verdict | REPRODUCED on unpatched #0; FIXED on single-fix #1 |
| Impact | Info disclosure β pgid/sid of every process on the system (no EPERM) |
| Class | CWE-862 Missing Authorization (POSIX non-compliance) |
| Severity | Info |
| Confidence | certain |
| Reproduced on | DragonFly 6.5-DEVELOPMENT #0 (Thu Jul 2 06:02:54 UTC 2026) |
| Fixed on | DragonFly 6.5-DEVELOPMENT #1 (Tue Jul 14 19:55:09 UTC 2026) |
| Kernel file | sys/kern/kern_prot.c |
Mechanism
sys_getpgid (sys/kern/kern_prot.c:106-131) and sys_getsid
(sys/kern/kern_prot.c:136-158) look up an arbitrary pid via pfind()
and return its process-group-id / session-id without any cross-session
visibility check. The code is simply:
/* sys_getpgid, lines 123-127 */
if (error == 0) {
lwkt_gettoken_shared(&pt->p_token);
sysmsg->sysmsg_result = pt->p_pgrp->pg_id; /* no p_trespass / session check */
lwkt_reltoken(&pt->p_token);
}
/* sys_getsid, lines 153-154 */
if (error == 0)
sysmsg->sysmsg_result = pt->p_session->s_sid; /* no visibility check */
POSIX.1-2017 (getpgid(2), getsid(2)) requires EPERM when the target
process is not in the caller's session. Contrast sysctl kern.proc
(sys/kern/kern_proc.c:1690,1718,1768) which applies PRISON_CHECK /
p_trespass before revealing process metadata.
Proof
leak_pgid.c (system-wide enumeration)
Scans pid 1..100000 and prints every successful getpgid/getsid as the
unprivileged maxx user (uid 1001).
Before fix (#0): enumerates 22 processes including init (pid 1),
sshd, getty, and unrelated sessions β with no EPERM:
pid 1 pgid 1 sid 1 pid 68 pgid 68 sid 68 ... 22 processes' pgid/sid enumerated as uid=1001 (no EPERM)
leak_xsess.c (definitive cross-session test)
Parent forks a child that calls setsid() to create a brand-new session,
then the parent (in the original session) probes the child's pgid/sid.
Before fix (#0):
[parent] pid=859 pgid=859 sid=859 uid=1001 [parent] probing child pid=860 (DIFFERENT session): getpgid(860) = 860 errno=0 (Undefined error: 0) getsid(860) = 860 errno=0 (Undefined error: 0) BUG DF-0037 REPRODUCED: parent (sid=859) leaked child's pgid/sid from a DIFFERENT session with no EPERM.
Fix
findings/poc/DF-0037/fix.diff β adds a session-equality + capability
check (mirroring the p_trespass pattern in sys/kern/kern_prot.c:1023)
to both syscalls:
if (pt->p_session != p->p_session &&
caps_priv_check(p->p_ucred, SYSCAP_NOPROC_TRESPASS)) {
error = EPERM;
} else {
sysmsg->sysmsg_result = pt->p_pgrp->pg_id; /* or pt->p_session->s_sid */
}
This matches the finding markdown's ## Recommended fix proposal
verbatim: same predicate, same capability, applied to both syscalls.
Validation (Phase 8)
| Phase | Kernel | Behavior |
|---|---|---|
Baseline #0 (unpatched) |
6.5-DEVELOPMENT #0 |
leak_xsess β errno=0, no EPERM; leak_pgid β 22 processes enumerated |
Single-fix #1 (built + installed) |
6.5-DEVELOPMENT #1 (sha256 c1819cd1..., build ts 19:55:09) |
leak_xsess β errno=EPERM for cross-session target ("FIXED"); leak_pgid β 3 processes (own session only); deterministic over 3 re-runs |
The fix closes the leak completely: only processes in the caller's own
session are returned; out-of-session targets correctly return EPERM. The
SYSCAP_NOPROC_TRESPASS capability preserves root's ability to inspect
any process (same mechanism as p_trespass).
Files in this evidence pack
leak_pgid.cβ minimal PoC: system-wide pgid/sid enumerationleak_xsess.cβ definitive PoC: parent vs setsid-child cross-session probe (added by runner)build.sh/run.shβ exact build/run commandsrun.logβ decisive baseline run (full output of both PoCs)fix_run.logβ decisive patched-kernel runfix_build_tail.txtβ kernel build log (rc=0)fix.diffβ git-apply-able fix (validated to apply + build + close the bug)env.txtβ guest environment (uname, cc, kern.version)manifest.jsonβ artifact catalog
Fix verification
fixedVALIDATED: baseline cross-session errno=0; patched EPERM. 22 procs -> 3 procs.
BEFORE: getpgid=860 errno=0. AFTER: getpgid=-1 errno=EPERM.
Confirmed kernel references
Detail
Exploit chain
none -- Info-level metadata disclosure (pgid/sid enumeration). No corruption.
Evidence (decisive lines)
BEFORE: getpgid(860)=860 errno=0 cross-session; 22 procs enumerated. AFTER: EPERM; 3 procs (own session).
PoC changes
Added leak_xsess.c (definitive cross-session), fix.diff (session check + SYSCAP_NOPROC_TRESPASS), VERDICT.md, manifest.json.
Verified recommended fix
Gate result in sys_getpgid(:125) and sys_getsid(:154): if(pt->p_session!=p->p_session && caps_priv_check(p->p_ucred,SYSCAP_NOPROC_TRESPASS)) error=EPERM. Matches finding proposal. Full diff in findings/poc/DF-0037/fix.diff.
Verdict
REPRODUCED. sys_getpgid/sys_getsid kern_prot.c:106-158 call pfind(arbitrary pid) + return pgid/sid with no session-equality check. Violates POSIX EPERM for out-of-session. maxx enumerates 22 processes incl init/sshd. Cross-session parent reads child pgid/sid errno=0.
No comments yet.