DF-5596 / verdict.json
{ "finding_id": "DF-5596", "status": "reproduced", "reproduced": true, "impact": "none", "confidence": "certain", "verdict": "genassym.c never emits GD_CURRENTLDT although struct mdglobaldata still has gd_currentldt (globaldata.h:78) and the standard-built global.s:66-67 consumes it via .globl/.set. Proven on the shipped kernel: global.o and /boot/kernel/kernel both carry an undefined GD_CURRENTLDT, the promised gd_currentldt export silently does not exist, zero relocations consume the dangling symbol, and the build never failed -- the genassym C<->asm contract guard is silently defeated for .set-consumed macros under this link configuration. No runtime memory-safety impact today (nothing references the missing symbol); the security relevance is the demonstrated silent-failure mode of the offset-contract enforcement itself. One-line fix validated with the exact kernel build rules: regenerated assym.s gains #define GD_CURRENTLDT 0x42d4 and the consumer probe resolves to an absolute symbol 0x42d4.", "exploit_chain": "", "evidence": "shipped_kernel_evidence.txt (nm global.o + kernel: U GD_CURRENTLDT, gd_currentldt absent, 0 relocs); nm_probe_unpatched.txt (bug under controlled build); nm_probe_fixed.txt (00000000000042d4 A gd_currentldt_probe); diff.fix_delta.txt (exactly one added define); diff.buildtree_vs_regen.txt (empty: regen identical to build tree); diff.assym_vs_checker.txt (176/176 offsets match independent TU)", "kernel_refs": [ "sys/platform/pc64/x86_64/genassym.c:230-239", "sys/platform/pc64/x86_64/global.s:66-67", "sys/platform/pc64/include/globaldata.h:78", "sys/platform/pc64/conf/files:129", "sys/conf/kern.post.mk:73-79", "sys/kern/genassym.sh:10-44" ], "poc_changes": "seed had no runnable PoC; authored probe_gdcl.s (mirrors global.s consumption shape), genassym_fixed.c (one added ASSYM line), offset_check.c (mechanically generated from genassym.c, separate-TU value cross-check). First runner attempt failed (-I. must resolve the kernel build dir; -nostdinc forbids stdio.h) -- fixed by cd $BD and a manual printf declaration; attempts=2.", "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": 1500, "guest_dirty": 0, "build_cmd": "sh build.sh (cc -c $(make -V CFLAGS minus -fno-common) -fcommon genassym.c; sh /usr/src/sys/kern/genassym.sh genassym.o > assym.s; cc -x assembler-with-cpp $(make -V ASM_CFLAGS) -c probe_gdcl.s)", "run_cmd": "sh run.sh", "code_hash": "b97bf4f254e9d56fdda936519b19f61cdbbb3f9fe12c61d1c9d4aaac6aaa1db8", "notes": "Non-corruption finding: targeted same-flags rebuild + probe assemble is the fix validation (full kernel reboot not required). Same silent-vanish mechanism leaves 7 more dangling undefined symbols from locore.s:41-47 (loc_PTmap..loc_PML4pml4e, dmapbase, dmapend -- pmap.h externs nothing defines); that cleanup belongs to locore.s/pmap.h, not genassym.c. vkernel64 global.s:65 has the identical dangling use. Checklist resolved: TF_R10/TF_R11 ARE defined (genassym.c:152-153, consumed exception.S:305-306); all 176 emitted offsets match an independent kernel-CFLAGS TU; zero hardcoded numeric struct displacements in any pc64/cpu .s consumer; MDGLOBALDATA_BASEALLOC_PAGES derives from sizeof in the same header so it cannot drift.", "recommended_fix": "Add ASSYM(GD_CURRENTLDT, offsetof(struct mdglobaldata, gd_currentldt)); to genassym.c (fix.diff); optionally also audit-remove the dead locore.s:41-47 aliases.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": true, "fix_verdict": "Baseline: probe.o carries U GD_CURRENTLDT and no gd_currentldt definition (assembly+link succeed). Patched (one ASSYM line, identical build flags): assym.s gains exactly #define GD_CURRENTLDT 0x42d4 and probe.o defines absolute gd_currentldt_probe=0x42d4. Bad behavior gone; contract restored.", "fix_evidence": "diff.fix_delta.txt, fix_gdcl_value.txt, nm_probe_unpatched.txt, nm_probe_fixed.txt" } |