DF-3197 / verdict.json
{ "finding_id": "DF-3197", "status": "reproduced", "reproduced": 1, "impact": "uid0_privesc", "confidence": "certain", "verdict": "devfs_dev_ioctl() (sys/vfs/devfs/devfs_rules.c:419) has no priv_check() and no jail check; the only gate is the 0600 root:wheel /dev/devfs node, which jailed uid 0 opens. Rule state is the global devfs_rule_list and APPLY/RESET walk the global devfs_mnt_list, so jailed root unhid host-hidden devices in its own jail devfs (opened /dev/zero from inside the jail) and rewrote the HOSTs /dev/console from 0600 to 0666 via a PERM rule with mntpoint /dev. Impact is a jail escape (jailed root -> host device access / host permission weakening) whenever the jails devfs shows the devfs control node (default on this guest: no /etc/devfs.rules shipped). Impact: jail escape (jailed root defeats the hosts devfs ruleset and rewrites host device permissions; full host uid=0 follows standardly from the unhide+perm primitives, e.g. raw-disk access, but was not executed to avoid destroying the guest disk).", "exploit_chain": "host mounts devfs for jail + hides mem/zero via rules -> jail(2) as uid 0 -> open /dev/devfs (0600, uid0 passes) -> DEVFS_RULE_ADD SHOW/PERM + APPLY * or /dev -> hidden nodes reappear in the jail (opened /dev/zero); host /dev/console becomes 0666; any device whose driver lacks its own jailed() check is reachable", "evidence": [ "run.log: JAIL-ESCAPE: unhidden + OPENED /dev/zero from inside jail", "run.log: [host] /dev/console mode post-jail: 0666 (pre: 0600)", "run.fixed.log: jailed ioctl now EPERM, host untouched" ], "kernel_refs": [ "sys/vfs/devfs/devfs_rules.c:419", "sys/vfs/devfs/devfs_rules.c:470", "sys/vfs/devfs/devfs_core.c:1912", "sys/vfs/devfs/devfs_core.c:1917-1931" ], "poc_changes": "initial PoC forgot mkdir /jail/dev; needed setvbuf before fork; SHOW does not bump mnt_namecache_gen so negative/positive namecache entries had to be flushed by linking a pid-unique alias; rules from earlier runs had to be CLEARed for idempotency", "attempts": 5, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 40, "guest_dirty": 1, "build_cmd": "cc -static -O -o jail_show jail_show.c", "run_cmd": "./jail_show", "code_hash": "767de016ab6a7e0072563a9ed8d76dafe7d949858969a6fcb221820cba95ee78", "notes": "privilege ceiling: on a non-jail host the ioctls are root-only (0600 node). The broken boundary is jail root vs host. /dev/mem un-hid and was stat-able from the jail; memio(4)s own jailed() check returned EPERM on open - driver-level defense devfs lacks.", "recommended_fix": "reject jailed callers in devfs_dev_ioctl(): if (jailed(curthread->td_ucred)) return EPERM;", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Tue Sep 8 10:25:07 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "jailed ioctls return EPERM (run.fixed.log); host /dev/console untouched; jail child cleanly fails", "fix_evidence": [ "DF-3197/run.fixed.log" ] } |