DF-4263 evidence pack — verdict =============================== Reproduced? NOT at runtime — hardware-gated (no AMD GPU on the audit guest, /dev/dri absent — env.txt/run.log). Defect: PROVEN at code level (certain): permanent, unbounded leak of kernel objects + BO references per CS ioctl, by an unprivileged render-node client. Proof chain ----------- 1. BO_HANDLES (the heavyweight variant): a. `amdgpu_cs_parser_init()` loop (amdgpu_cs.c:151-222) dispatches every BO_HANDLES chunk (:200-211) to `amdgpu_cs_bo_handles_chunk()` with no duplicate guard. b. `amdgpu_cs_bo_handles_chunk()` (:78-101) calls `amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number, &p->bo_list)` — the list is stored via the out-param, replacing any previous value of `p->bo_list` without dropping it. c. `amdgpu_bo_list_create()` (amdgpu_bo_list.c:61-151) returns the list with `kref_init` = 1 (:83) and holds one `amdgpu_bo_ref()` per entry (:103). The only put that ever runs for it is `amdgpu_cs_parser_fini()` (amdgpu_cs.c:807-808, `amdgpu_bo_list_put`) — which fires exactly once, for the LAST list. The first list object (kmalloc'd, sizeof(list) + n*sizeof(entry)) and every BO reference it holds leak permanently. d. Rate: bo_number is user-chosen (bounded only by the kvmalloc in amdgpu_bo_list.c:226); the same GEM handle may appear many times. Each CS ioctl therefore leaks an attacker-chosen number of BO references (each BO ≥ PAGE_SIZE of GTT/VRAM + kernel structs) plus one list. GEM handles are created once and reused across CS calls, so N CS ioctls × M entries = N×M leaked refs with only M live BOs — unbounded exhaustion without allocating more GPU memory. 2. FENCE variant: `amdgpu_cs_user_fence_chunk()` (:37-76) takes `amdgpu_bo_ref()` (:50) and assigns `p->uf_entry.tv.bo = &bo->tbo` (:52). A second FENCE chunk overwrites the pointer; fini unrefs once (:815-819). Net +1 BO ref per extra FENCE chunk. 3. SYNCOBJ_OUT variant: `amdgpu_cs_process_syncobj_out_dep()` (:1138-1163) allocates a fresh `p->post_dep_syncobjs` array (:1148) and resets `p->num_post_dep_syncobjs = 0` (:1151). A second SYNCOBJ_OUT chunk (the whole `amdgpu_cs_dependencies()` loop :1170-1188 processes every chunk) orphans the first array together with every `drm_syncobj` reference taken by `drm_syncobj_find()` (drm_syncobj.c:83-94 — the reference must be released with drm_syncobj_put; fini only puts the last array, amdgpu_cs.c:797-799). 4. The only existing duplicate guard (amdgpu_cs.c:587-589) rejects ioctl-arg `bo_list_handle` combined with a BO_HANDLES chunk — it does NOT protect chunk-vs-chunk duplication, which is what the PoC uses. Guest verification performed ---------------------------- - trigger compiles (build.log); runs to the hardware gate (run.log) - baseline amdgpu_cs.c in-tree compile rc=0 with -Werror (kmod_baseline_build.log) - stacked fix (DF-4262+4263+4264+4265 diffs) applied via `patch -p1` (hunks at 190/209/1155) and recompiled rc=0 with -Werror (fix_build.log) — fix compiles; runtime leak measurement needs HW. Exploit chain: memory-exhaustion DoS only (no memory-safety violation: the leaked objects stay valid, they are simply never freed). Recommended fix: reject duplicate stateful chunks (fix.diff). ## Fix status (batch validation) Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.