DF-5102 / verdict.json
{ "finding_id": "DF-5102", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "apple_fw_probe() passes kgetenv() results straight to kfreeenv() with no NULL check (apple_fw.c:112-113). When the kernel environment is dynamic (standard post-loader state) and an smbios.* entry is absent, kgetenv returns NULL, kfreeenv(NULL) reaches kfree(NULL), and DragonFlys _kfree panics outright (kern_slaballoc.c:1407). The sink was reproduced on the audit guest with a KLD executing the exact call sequence: panic: trying to free NULL pointer with a backtrace through the module load path; the guest wedged in DDB and stopped answering ssh. Driver-path reachability additionally requires Apple-flagged FADT OEM ID plus a present-but-SMBIOS-less environment (driver is optional apple_fw acpi, only LINT64 or root kldload), which is why this is Low severity rather than a default-config DoS.", "exploit_chain": "", "evidence": "panic.txt / run.log: panic: trying to free NULL pointer with _kfree+0x558 -> df5102_load+0x6e backtrace after kgetenv returned NULL (product=0 biosver=0). console_full.log has the full session; env.txt documents guest kenv (dynamic, smbios vars present on THIS guest, RSDP OEM BOCHS explaining why the drivers own probe path is not drivable here); build.log shows the clean KLD build. VERDICT.md traces the source chain apple_fw.c:107-113 -> kern_environment.c:331-336 -> kern_slaballoc.c:1407.", "kernel_refs": [ "sys/dev/apple/fw/apple_fw.c:107", "sys/dev/apple/fw/apple_fw.c:112", "sys/dev/apple/fw/apple_fw.c:113", "sys/kern/kern_environment.c:228", "sys/kern/kern_environment.c:331", "sys/kern/kern_slaballoc.c:1407", "sys/conf/files:1235" ], "poc_changes": "Original trigger idea was load apple_fw and let it probe \u2014 impossible on the guest (FADT OEM is BOCHS, not APPLE). Replaced with a mechanism PoC KLD that runs the identical kgetenv(absent)+kfreeenv sequence. Three attempts were needed: (1) first PoC used the real variable names, which exist on the guest, so no NULL occurred (this itself confirms the precondition analysis); (2) second attempt hit a module-name collision with the already-loaded first build (module lacked MOD_UNLOAD); (3) renamed the module (df5102b), added MOD_UNLOAD, used genuinely-absent names -> panic reproduced. Also had to make helpers static to satisfy -Werror=missing-prototypes in the guest kernel build.", "attempts": 3, "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": 900, "guest_dirty": 0, "build_cmd": "cd /root/df5102 && printf KMOD=df5102b\\nSRCS=df5102_nullfree.c\\n.include <bsd.kmod.mk>\\n > Makefile && make", "run_cmd": "kldload /root/df5102/df5102b.ko # as root; expect immediate panic + DDB wedge", "code_hash": "c7b41aa62b9044f69618fd272db40318c316be019443640ceff4f681ce42bd0d", "notes": "Guest reset to clean-source snapshot after panic capture (vm.sh reset with-src). The not-a-bug half of the chain, for the record: ksnprintf %s is NULL-safe ((null), subr_prf.c:750-753), so the format call itself cannot crash; only kfreeenv can.", "recommended_fix": "NULL-guard both kfreeenv() calls in apple_fw_probe (or make kfreeenv NULL-safe kernel-wide).", "fix_status": "not_testable", "fix_kernel_uname": "", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Baseline panic reproduced. A patched-driver run cannot be exercised on this guest: apple_fw is optional apple_fw acpi (not in X86_64_GENERIC) and its identify/probe is gated on FADT OemId APPLE (apple_fw.c:58-67) while this guest provides BOCHS (env.txt) with no in-guest way to override the FADT OEM ID. The two-line NULL guard in fix.diff turns the failing calls into no-ops; the PoCs own non-NULL branch (attempt 1, vars present) already ran that path harmlessly.", "fix_evidence": "env.txt (RSDP OEM BOCHS ), VERDICT.md Fix validation section, fix.diff." } |