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)
PoC verification
Evidence pack
findings/poc/DF-0136 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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.
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): redirectsVARSYM_SYS -> VARSYM_PRISON(level = VARSYM_PRISON) whentd->td_ucred->cr_prison != NULL.varsymfind()(:400-408, used byvarsym_get/ namei): for theVARSYM_SYS_MASKlookup, if jailed it searchestd->td_ucred->cr_prison->pr_varsymsetinstead ofvarsymset_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
fixedvalidated
see evidence pack
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.
No comments yet.