DF-2800 / verdict.json
{ "finding_id": "DF-2800", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "REPRODUCED: uid 0 inside a completely ordinary jail (jail(2) v1, path /tmp, no IPs) successfully stepped the HOST system clock backward 30 seconds with settimeofday(2) (run.log: 'settimeofday: OK (stepped clock -30s)', host clock observed 1788266899 -> 1788266871 by the unjailed parent). Root cause is in prison_priv_check (kern_jail.c): SYSCAP_NOSETTIME is explicitly allowed in jails (:891-892), and every group-2 capability checked via caps_priv_check is blanket-allowed because kern_caps.c rewrites the cap to its group meta value before calling prison_priv_check โ SYSCAP_NOSETTIME (0x28) becomes 2 == SYSCAP_SENSITIVEROOT, allowed at kern_jail.c:858-861. settime() only consults the global securelevel (kern_time.c:134-140); pr_securelevel is dead code. Same gate covers clock_settime, adjtime and ntp_adjtime. On the patched kernel (leaf case -> EPERM + kern_caps.c forwards the original cap) the identical PoC gets 'settimeofday: FAILED: Operation not permitted' with the host clock unchanged. Impact is a jail-isolation break (host-wide clock integrity): mapped to enum 'dos' because the reporting categories lack an integrity class โ realistic damage is skew/step/freeze of the shared host clock degrading NTP/TLS/kerberos/cron/logging for the host and all co-resident jails.", "exploit_chain": "jailed uid-0 (the normal tenant model) -> settimeofday/clock_settime/adjtime/ntp_adjtime -> host-global clock manipulation. No memory-safety primitive; no uid0-on-host route.", "evidence": [ "findings/poc/DF-2800/run.log โ stock: settimeofday OK, host clock -28s, REPRODUCED line", "findings/poc/DF-2800/run.patched.log โ fixed: EPERM, NOT-REPRODUCED, delta=0, securelevel -1 (i.e. no securelevel protection even before fix)" ], "kernel_refs": [ "sys/kern/kern_jail.c:891", "sys/kern/kern_jail.c:858", "sys/kern/kern_caps.c:336-348", "sys/kern/kern_time.c:287", "sys/kern/kern_time.c:661", "sys/kern/kern_time.c:753", "sys/kern/kern_ntptime.c:304", "sys/sys/jail.h:125" ], "poc_changes": "none essential โ pack seed compiled and ran first try; libc has no jail(3) wrapper assumption removed by using syscall(SYS_jail=338) directly.", "attempts": 1, "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": 60, "guest_dirty": 0, "build_cmd": "cc -O2 -o jailsettime jailsettime.c", "run_cmd": "./jailsettime (as root; forks, child jails itself, then settimeofday t1-30s)", "code_hash": "ede464f069d82ee7190edae140eaa0e9d8c94ccd9e5d93f3a3631843c3f7e39f", "notes": "FreeBSD denies clock setting in jails (PRIV_CLOCK_SETTIME -> EPERM); DragonFly allows it. Even at host securelevel>1 the residual power is freeze/double-speed (settime() comments). Fixed kernel = #1 Tue Sep 1 13:39:40 UTC 2026.", "recommended_fix": "prison_priv_check: SYSCAP_NOSETTIME -> EPERM, plus kern_caps.c must pass the ORIGINAL (un-rewritten) capability to prison_priv_check so per-leaf policy cannot be bypassed through the group-meta rewrite.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Tue Sep 1 13:39:40 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Patched kernel: jailed settimeofday returns EPERM and the host clock is unchanged (delta=0 vs -28s on stock). The exact error path (child jailed, jid assigned) is exercised in both runs.", "fix_evidence": "findings/poc/DF-2800/run.patched.log; fix.diff (kern_jail.c leaf deny + kern_caps.c ocap forwarding)" } |