DF-3573 / verdict.json
{ "finding_id": "DF-3573", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Legacy-firmware size-check bypass in cik_init_microcode(): only the pfp block does goto out after a Bogus-length error (cik.c:2060); me/ce/mec/rlc/sdma/mc/smc set err=-EINVAL and continue (cik.c:2080-2252), and every later successful request_firmware() zeroes err, so an all-legacy system accepts a wrong-size firmware whenever any subsequent fw loads cleanly (final guard at cik.c:2265 only fires when mixing new/old). The legacy loaders then read CIK_*_UCODE_SIZE*4 bytes from the fw buffer regardless of its size (cik.c:3966/3973/3980, 4318/4326, 6001-6002; cik_sdma.c:501/508) -> heap OOB read of up to CONSTANT*4-datasize bytes (7552 B for a 1 KiB ME file; 15.7 KiB worst case for MEC). Kernel-level verification impossible on this guest: virtio VGA only (0x1234:0x1111), no CIK device, radeon.ko never attaches. Logic-level reproduction on the guest is deterministic (3/3): baseline accepts the truncated ME fw and prints the 7552-byte OOB span; the FIXED build (fix.diff: 7x goto out, pfp parity) rejects with err=-EINVAL and releases everything at out:. Precondition (root-installed wrong-size fw module) gates this to defense-in-depth, consistent with DF-1119s rating of the sibling new-format issue. Upstream Linux v4.7 verified byte-identical (asymmetric goto out) -- live upstream bug, cve_match=equivalent.", "exploit_chain": "", "evidence": "run.log + run.2.log: S1: truncated legacy ME firmware -> err=0 (ACCEPTED) ... me_fw(1024B) and OOB READ: me_fw holds 1024 bytes, cik.c:3980 loop reads 8576 -> 7552 bytes past allocation; FIXED section of run.log: err=-22 (rejected), installed fw: (none); S2 control (truncated pfp) rejected in BOTH modes proving the asymmetry; VERDICT.md has the full 5-step source chain and the upstream diff note; env.txt records the guest has no radeon hardware (vgapci0 chip=0x11111234).", "kernel_refs": [ "sys/dev/drm/radeon/cik.c:2056", "sys/dev/drm/radeon/cik.c:2080", "sys/dev/drm/radeon/cik.c:2103", "sys/dev/drm/radeon/cik.c:2126", "sys/dev/drm/radeon/cik.c:2164", "sys/dev/drm/radeon/cik.c:2187", "sys/dev/drm/radeon/cik.c:2216", "sys/dev/drm/radeon/cik.c:2248", "sys/dev/drm/radeon/cik.c:2265", "sys/dev/drm/radeon/cik.c:3966", "sys/dev/drm/radeon/cik.c:3973", "sys/dev/drm/radeon/cik.c:3980", "sys/dev/drm/radeon/cik.c:4318", "sys/dev/drm/radeon/cik.c:4326", "sys/dev/drm/radeon/cik.c:6001", "sys/dev/drm/radeon/cik_sdma.c:501", "sys/dev/drm/radeon/radeon_ucode.h:38" ], "poc_changes": "No seeded PoC existed (pass-2 new finding). Harness transcribed statement-for-statement from cik.c:2049-2297 with the exact constants; initial version under-modeled err = request_firmware() assigning 0 on success (the very clobber under test) and was corrected; out: release-all on error modeled per cik.c:2275-2297.", "attempts": 3, "guest_uname": "DragonFly dfbsd 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": 9, "guest_dirty": 0, "build_cmd": "cc -O -Wall -o fwsize_bypass fwsize_bypass.c && cc -O -Wall -DFIXED -o fwsize_bypass_fixed fwsize_bypass.c", "run_cmd": "./run.sh", "code_hash": "238bfd537df6a568699c1ad2f495125770b9532d86cbd995a8fec4cd14e7d381", "notes": "Pass-2 deep audit of cik.c additionally killed: IH ring walk OOB (entries 16B-aligned within 64KB ring, r600_ih_ring_init cik.c:8685); DCE8 watermark div-by-zero (divisors are vbios-derived clocks, upstream-identical, cik.c:9132-9134); cp_m1p3 copy-paste in cik_irq_set (pipe 3 never used, cosmetic); restart_ih wptr re-read race (upstream-identical benign, cik.c:8126-8132); workqueue-vs-unload (cik.c owns no works -- hotplug/dp/thermal belong to radeon_irq_kms.c/radeon_pm.c); mc wrong-size acceptance (loader self-bounded by datasize/4 at cik.c:1880, subsumed into this finding). DF-1119 (new-format header field walks) intentionally not re-reported. [orchestrator: poc status normalized from not_testable->not_reproduced; source-verified, CIK hardware absent]", "recommended_fix": "Add goto out; after every Bogus-length err=-EINVAL in cik_init_microcode (7 sites, pfp-parity) -- see fix.diff; optionally also clamp legacy loader loops to min(CONSTANT, fw->datasize/4).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (7x goto out, patch -p0 clean against a scratch copy) flips the harness from ACCEPTED+7552B-OOB to rejected-with-release-all while leaving both control scenarios unchanged (run.log FIXED section). A patched-kernel boot test is impossible on this guest: no CIK radeon device exists, so cik_init_microcode cannot run. fix validated at logic level only.", "fix_evidence": "run.log === FIXED (with fix.diff: goto out after every bogus length) === -> S1 ... err=-22 (rejected), installed fw: (none); S3 control unchanged (err=0, all fw ok); fix.diff dry-run/apply log in the analysis transcript (patch -p0: 7 hunks applied)." } |