DF-4878 / verdict.json
{ "finding_id": "DF-4878", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "dal_i2caux_release_engine() runs unsynchronized (the DAL2 mutex was dropped \u2014 i2caux.h:91) and stores engine->ddc = NULL two statements after dal_ddc_close(); a concurrent acquirer of the same per-line engine can open the just-closed pins and install its ddc pointer inside that window, which the release then wipes \u2014 the SW-i2c submit path dereferences the NULL ddc immediately, and the AUX path ends in dal_ddc_close(NULL) whose callee dereferences ddc->pin_clock without a NULL guard (gpio_service.c:587-590) -> fatal trap. Narrow-window display-path panic; not runnable on the audit guest because its only VGA is QEMU std VGA so amdgpu never attaches.", "exploit_chain": "T1 release between dal_ddc_close (i2caux.c:426) and engine->ddc=NULL (:428) while T2 acquire passes the now-clear pin-open guard (gpio_base.c:59-70) and sets engine->ddc=ddc (aux_engine.c:75 / i2c_sw_engine.c:473) -> T1 wipes it -> T2 submits (SW: i2c_sw_engine.c:491 NULL ddc) or T2 releases (i2caux.c:426 dal_ddc_close(NULL) -> gpio_service.c:590 NULL deref) -> panic", "evidence": "VERDICT.md (interleaving with every load/store cited); README.md; env.txt (vgapci0 8086:1111 std VGA, amdgpu.ko unloaded)", "kernel_refs": [ "sys/dev/drm/amd/display/dc/i2caux/i2caux.c:420", "sys/dev/drm/amd/display/dc/i2caux/i2caux.c:426", "sys/dev/drm/amd/display/dc/i2caux/i2caux.c:428", "sys/dev/drm/amd/display/dc/i2caux/i2caux.h:91", "sys/dev/drm/amd/display/dc/i2caux/aux_engine.c:75", "sys/dev/drm/amd/display/dc/i2caux/i2c_sw_engine.c:473", "sys/dev/drm/amd/display/dc/i2caux/i2c_sw_engine.c:491", "sys/dev/drm/amd/display/dc/gpio/gpio_service.c:587", "sys/dev/drm/amd/display/dc/gpio/gpio_base.c:59" ], "poc_changes": "n/a \u2014 no AMD GPU on guest (hardware blocker); race proven by code layout", "attempts": 0, "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": 0, "guest_dirty": 0, "build_cmd": "", "run_cmd": "", "code_hash": "", "notes": "Sinks are panic-only (wiped value is NULL); the wrong-owner-close variant (T1 closes T2s pins mid-transaction) corrupts gpio pin state but is not a controlled write. dce110s unsynchronized i2c_hw_buffer_in_use check-then-act (i2caux_dce110.c acquire_i2c_hw_engine) is the same missing-mutex family but lives in a different file (DF-4808 adjacent).", "recommended_fix": "Guard dal_ddc_close(engine->ddc) against NULL (sink fix, fix.diff) and restore the DAL2 per-i2caux mutex across acquire->submit->release (root fix)", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "No AMD GPU on guest; the guarded close removes the panic sink by construction; full serialization needs the mutex (recommended in finding)", "fix_evidence": "fix.diff (git apply --check OK)" } |