DF-2772 / verdict.json
{ "finding_id": "DF-2772", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "link_elf_obj stores each REL/RELA section's sh_info verbatim as the relocation target (sys/kern/link_elf_obj.c:775/:791) and later turns any target that is not a loaded PROGBITS/NOBITS section into panic('lost base for reltab/relatab') (:975-977, :1002-1004, and link_elf_obj_reloc_local :1243-1245/:1265-1267, reached from kldload via :818 and from boot preload via :368) instead of rejecting the file. A 514-byte crafted ET_REL module with one .rela whose sh_info=0 panics the stock guest deterministically (reproduced twice on fresh resets) โ panic backtrace link_elf_obj_reloc_local <- link_elf_obj_load_file <- sys_kldload. Robustness/DoS only (no write primitive); trigger is root-supplied (SYSCAP_NOKLD), and the same panic from the preload path converts a corrupted boot module into a boot-time brick. fix.diff validates sh_info at scan time (elf_obj_reloc_target_ok) and converts the panics to ENOEXEC error returns; on rebuilt kernel #1 the same module is cleanly rejected ('Unsupported file type', RC=1, no panic, guest up).", "exploit_chain": "root crafts module (gen_module.py mode=panic-rela, .rela sh_info=0) -> kldload -> link_elf_obj_load_file -> link_elf_obj_reloc_local -> findbase()==0 -> panic('lost base for relatab') -> kernel halt in ddb. No memory corruption and no unprivileged reach (SYSCAP_NOKLD); ceiling is deterministic panic/DoS.", "evidence": [ "panic.txt โ baseline serial console: panic: lost base for relatab with full backtrace through link_elf_obj_load_file and sys_kldload", "run.log โ baseline (2 runs, ssh hang + panic) vs patched (clean rejection RC=1) transcripts", "gen_module.py โ trigger generator (mode panic-rela): shdr[5] type=SHT_RELA size=0x18 link=2 info=0", "build.log โ full untrimmed nativekernel build of the fix (-Werror clean)", "VERDICT.md โ path:line trace incl. preload reachability and all four panic sites", "fix.diff โ scan-time sh_info validation + panic-to-error conversion, baseline-vs-patched validated" ], "kernel_refs": [ "sys/kern/link_elf_obj.c:355", "sys/kern/link_elf_obj.c:775", "sys/kern/link_elf_obj.c:791", "sys/kern/link_elf_obj.c:975", "sys/kern/link_elf_obj.c:1003", "sys/kern/link_elf_obj.c:1244", "sys/kern/link_elf_obj.c:1266" ], "poc_changes": "n/a โ trigger authored fresh (hand-crafted ET_REL); no prior seed for this finding", "attempts": 2, "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": "python3 gen_module.py df2772.ko panic-rela", "run_cmd": "vm.sh run_root 'kldload /tmp/df2772.ko' (expect panic 'lost base for relatab' on stock; clean RC=1 rejection on patched)", "code_hash": "352c5bb633e0445b61c03e12fee9bc20428b01d5c4debe40506de0c2410120d2", "notes": "Fix validated with a single combined kernel build covering DF-2771/2772/2773. Guest reset to clean-source snapshot after verification. Same defect class exists in the preload path (boot-time). Severity Low per DF-0040/0041/0042 calibration (root-supplied module input).", "recommended_fix": "Validate REL/RELA sh_info at scan time (index < e_shnum and target is a to-be-loaded PROGBITS/NOBITS section) and return ENOEXEC instead of panic()ing at the findbase() call sites.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Tue Sep 1 01:04:57 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 rejects the identical module with ENOEXEC ('linker_load_file: Unsupported file type' in dmesg, RC=1), no panic, guest stays up; baseline kernel #0 panics on the same input.", "fix_evidence": "run.log (baseline vs patched), build.log (kernel #1 build), dmesg 'linker_load_file: Unsupported file type'" } |