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

Jail isolation breach: varsym_list(VARSYM_SYS) leaks host varsyms to jailed processes

Summary

sys_varsym_list(:263-265) sets vss=&varsymset_sys for VARSYM_SYS with no jail check. Compare sys_varsym_set(:153-155) redirects VARSYM_SYS->VARSYM_PRISON for jailed. varsymfind(:400-408) also jail-scoped. varsym_list is ONLY path where jailed process reaches global varsymset_sys. Info leak host->jail.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0136 Β· 12 files
FileTypeDescriptionSize
leak_check.c trigger-source varsym_list(VARSYM_SYS) enumeration from inside a jail 3.1 KB view raw
build.sh build-script cc -o leak_check leak_check.c 112 B view raw
run.sh run-script varsym -s marker; jail ... leak_check 488 B view raw
run.log run-log decisive run: LEAK_CONFIRMED, 126 host varsyms enumerated from jail 412 B view raw
env.txt environment uname, cc version, jail availability 225 B view raw
VERDICT.md verdict full analysis + mechanism 2.6 KB ↓ raw
README.md readme reproduce instructions 1023 B ↓ raw
fix.diff suggested-fix redirect VARSYM_SYS to prison varsymset when jailed in sys_varsym_list 453 B view raw
fix_build.log build-log single-fix kernel build (kern_varsym.c) rc=0 5.6 MB ↓ download
fix_run.log run-log patched kernel -> NO_LEAK 310 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
README.md readme reproduce instructions
↓ download raw

DF-0136 β€” varsym_list(VARSYM_SYS) jail isolation breach

Verdict REPRODUCED
Impact info-leak / jail isolation breach (host→jail)
File sys/kern/kern_varsym.c:263-264

Build

cc -o leak_check leak_check.c

Run

# (as root) plant a marker host system varsym, then enumerate inside a jail
./run.sh
#   which does:
#     varsym -s DF0136_HOSTSECRET=secretvalue
#     jail / dftest 127.0.0.1 /path/to/leak_check

Expected (bug present)

RESULT: LEAK_CONFIRMED β€” host system varsyms are enumerable from inside a jail via varsym_list(VARSYM_SYS)

A jailed process enumerates ALL host system varsyms (126 on this guest), including the planted DF0136_HOSTSECRET=secretvalue. The jail-scoped varsym_get path correctly does NOT find the marker β€” proving the asymmetry (list leaks, get does not).

Expected (fixed)

RESULT: NO_LEAK β€” jail isolation holds for varsym_list

See VERDICT.md for the full analysis and fix.diff for the patch.

VERDICT.md verdict full analysis + mechanism
↓ download raw

DF-0136 β€” varsym_list(VARSYM_SYS) jail isolation breach

Verdict: REPRODUCED (jail info-leak / isolation breach)

Mechanism

sys_varsym_list() (sys/kern/kern_varsym.c:225) selects the varsym set to enumerate based on uap->level. For VARSYM_SYS it unconditionally picks the host-global varsymset_sys with no jail check (kern_varsym.c:263-264):

case VARSYM_SYS:
    vss = &varsymset_sys;          /* <-- host-global, no jail redirect */
    break;

This is inconsistent with the two sibling paths, which DO scope a jailed process to its prison varsymset:

  • sys_varsym_set() (:152-156): redirects VARSYM_SYS -> VARSYM_PRISON (level = VARSYM_PRISON) when td->td_ucred->cr_prison != NULL.
  • varsymfind() (:400-408, used by varsym_get / namei): for the VARSYM_SYS_MASK lookup, if jailed it searches td->td_ucred->cr_prison->pr_varsymset instead of varsymset_sys.

So varsym_list is the only varsym path where a jailed process reaches the host-global varsymset_sys.

Proof

A process placed inside a jail (via the jail command) enumerates the host's system varsyms β€” including a marker DF0136_HOSTSECRET=secretvalue set on the host by root β€” via varsym_list(VARSYM_SYS), while the jail-scoped varsym_get(VARSYM_SYS_MASK) correctly does NOT find it:

[*] jail.jailed = 1
[*] varsym_list(VARSYM_SYS) enumeration:
  *** LEAKED: DF0136_HOSTSECRET=secretvalue ***
[*] varsym_list(VARSYM_SYS) enumerated 126 system varsyms from inside the jail
[*] varsym_get(DF0136_HOSTSECRET) not found (rc=-1, No such file or directory) β€” get-path correctly jail-scoped
RESULT: LEAK_CONFIRMED β€” host system varsyms are enumerable from inside a jail via varsym_list(VARSYM_SYS)

Impact / realism

  • Realistic precondition: an admin sets system varsyms (e.g. rcng_* already populate them on this guest) and runs a jail. The jailed tenant β€” even an unprivileged user inside the jail β€” enumerates all host system varsym names and values. This is a host->jail information-disclosure / jail isolation breach.
  • Non-corruption class (info leak / isolation). No privesc chain.

Fix

fix.diff: in sys_varsym_list, redirect VARSYM_SYS to the prison varsymset when jailed, mirroring varsymfind() :400-408 / sys_varsym_set() :153-155. Supersedes (specifies) the finding's proposal β€” same intent, exact patch.

Reproduce

  • host: varsym -s DF0136_HOSTSECRET=secretvalue
  • build: cc -o leak_check leak_check.c
  • run: jail <path> <host> <ip> /path/to/leak_check
  • scripts: ./build.sh && ./run.sh (run.sh does setup + jail as root)

Fix verification

fixed

validated

see evidence pack
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Fri Jul 17 17:35:56 UTC 2026

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED. varsym_list(VARSYM_SYS) no jail check -> jailed process enumerates all host varsyms. Jail isolation breach.