DF-4263 / verdict.json
{ "finding_id": "DF-4263", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Code-certain unprivileged kernel reference leak family: duplicate AMDGPU_CHUNK_ID_BO_HANDLES / _FENCE / _SYNCOBJ_OUT chunks in one CS ioctl overwrite parser state (p->bo_list at amdgpu_cs.c:88-89; p->uf_entry.tv.bo at :52; p->post_dep_syncobjs at :1148-1151) without dropping the previous objects; amdgpu_cs_parser_fini() releases each exactly once (:797-799, :807-808, :815-819), so the first bo_list plus every amdgpu_bo ref it holds (amdgpu_bo_list.c:83,103), the first user-fence bo ref, and the first syncobj array + all its drm_syncobj refs leak permanently. Each CS can leak an attacker-chosen number of BO refs (same GEM handle repeated in the entries array), giving unbounded kernel-memory/GTT exhaustion by an unprivileged render-node client. Runtime reproduction hardware-gated on this guest (no AMD GPU, /dev/dri absent), hence untested; the leak is fully proven at code level.", "exploit_chain": "Resource-exhaustion DoS only - leaked objects remain valid, are simply never freed; no memory-safety violation.", "evidence": "dup_chunk_leak.c (two BO_HANDLES chunks x 64 duplicate handles x 1000 rounds); run.log (hardware gate); kmod_baseline_build.log + fix_build.log (in-tree -Werror compile before/after the duplicate-rejection guards).", "kernel_refs": [ "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:151", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:200", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:78", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:88", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:52", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:1148", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:797", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:807", "sys/dev/drm/amd/amdgpu/amdgpu_cs.c:815", "sys/dev/drm/amd/amdgpu/amdgpu_bo_list.c:83", "sys/dev/drm/amd/amdgpu/amdgpu_bo_list.c:103", "sys/dev/drm/drm_syncobj.c:83" ], "poc_changes": "Trigger written from scratch: embeds the 24-byte drm_amdgpu_bo_list_in as chunk kdata (>=6 dwords passes the :202 size check), entries supplied via bo_info_ptr user pointer, plus one minimal valid IB chunk so the CS survives ib_fill.", "attempts": 1, "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": 90, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o dup_chunk_leak dup_chunk_leak.c [in-tree fix-compile: cd /usr/src/sys/dev/drm/amd/amdgpu && make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC amdgpu_cs.o]", "run_cmd": "./dup_chunk_leak", "code_hash": "cb1d4c8cf23079286647c2ecf96ba095a17112acb77fd38ec00e47bdf7b40601", "notes": "poc status untested = runtime verification blocked by absent AMD GPU (schema has no not_testable for poc_results). Compile-only fix validation on guest; guest reset with-src before return.", "recommended_fix": "Reject duplicate stateful chunks: -EINVAL when p->uf_entry.tv.bo (FENCE), p->bo_list (BO_HANDLES) or p->post_dep_syncobjs (SYNCOBJ_OUT) is already set.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (three duplicate-rejection guards) applied on the guest stacked with the other amdgpu_cs.c fixes (hunks @190/@209/@1155) and compiled in-tree with -Werror rc=0 (fix_build.log). Runtime leak-measurement before/after impossible (no AMD GPU); compile-only validation.", "fix_evidence": "fix_build.log rc=0; guest patch output Hunk #1 succeeded at 190 / #2 at 209 / #3 at 1155." } |