Use-after-free in reset functions when kzalloc fails (connector/crtc/plane state)
Summary
amdgpu_dm_connector_funcs_reset (:3190), dm_crtc_reset_state (:2961), dm_drm_plane_reset (:3426) all free existing state then only assign new state inside if(state)/if(WARN_ON). On OOM connector->state/crtc->state/plane->state left pointing at freed memory. Unprivileged local user under memory pressure triggers reset -> UAF on next property read or state duplication. Info leak of freed heap + potential code execution with slab grooming. Fix: always call __drm_atomic_helper_*_reset even on OOM (assigns NULL).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1153 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | Full source trace + reachability analysis (3 reset functions) | 4.1 KB | β raw |
| fix.diff | suggested-fix | Assign NULL to *->state on OOM in all 3 reset fns (git apply-able, validated) | 818 B | view raw |
| build.sh | build-doc | Documents why no executable PoC is possible | 350 B | view raw |
| run.sh | run-doc | Documents why runtime trigger is impossible on this guest | 176 B | view raw |
| env.txt | environment | uname + kernel symbol inventory proving amdgpu absent | 348 B | view raw |
| README.md | readme | human reproduce doc | 826 B | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1153 β Use-After-Free in amdgpu_dm reset functions on OOM
Result
NOT REPRODUCED on this guest. Real source-level defense-in-depth bug;
fix authored. See VERDICT.md for the full analysis.
Build & run
./build.sh # documents why no executable PoC is possible ./run.sh # documents why runtime trigger is impossible
Reachability summary
- amdgpu_dm is part of amdgpu, not in
X86_64_GENERIC(0 symbols) - No AMD GPU on the QEMU guest, no
/dev/dri - Trigger needs memory pressure during DRM atomic reset on AMD hardware
Fix
fix.diff β assign NULL to *->state on the OOM path of all three
reset functions (amdgpu_dm_connector_funcs_reset, dm_crtc_reset_state,
dm_drm_plane_reset) at sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c.
Applies cleanly with git apply.
DF-1153 β Use-After-Free in amdgpu_dm reset functions on kzalloc failure
Verdict
NOT REPRODUCED on this guest (defense-in-depth source bug confirmed; path unreachable on the default GENERIC DragonFlyBSD kernel running in QEMU). Real source-level defect; fix.diff authored.
Mechanism (source trace, bug confirmed real)
Three amdgpu_dm atomic-helper reset callbacks share the same broken "destroy-then-alloc" pattern that leaves a dangling pointer on OOM:
amdgpu_dm_connector_funcs_reset β sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:3190
void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
{
struct dm_connector_state *state = to_dm_connector_state(connector->state);
if (connector->state)
__drm_atomic_helper_connector_destroy_state(connector->state); /* clears fields, keeps pointer */
kfree(state); /* L3198: FREED */
state = kzalloc(sizeof(*state), GFP_KERNEL); /* L3200 */
if (state) { /* L3202: ONLYassigns on success */
...
__drm_atomic_helper_connector_reset(connector, &state->base); /* L3209: sets connector->state */
}
/* OOM path: connector->state STILL points at the freed memory => UAF */
}
dm_crtc_reset_state β sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:2961
static void dm_crtc_reset_state(struct drm_crtc *crtc)
{
struct dm_crtc_state *state;
if (crtc->state)
dm_crtc_destroy_state(crtc, crtc->state); /* L2966: frees */
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (WARN_ON(!state)) /* L2969 */
return; /* crtc->state STILL points at freed memory */
crtc->state = &state->base; /* L2972: only on success */
...
}
dm_drm_plane_reset β sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:3426
static void dm_drm_plane_reset(struct drm_plane *plane)
{
struct dm_plane_state *amdgpu_state = NULL;
if (plane->state)
plane->funcs->atomic_destroy_state(plane, plane->state); /* L3431: frees */
amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
WARN_ON(amdgpu_state == NULL);
if (amdgpu_state) { /* L3436: only on success */
plane->state = &amdgpu_state->base;
...
}
/* OOM path: plane->state STILL points at the freed memory */
}
If kzalloc() fails (memory pressure), each function has already freed the
old state but bails out before assigning NULL (or a fresh object) to
connector->state / crtc->state / plane->state. The next DRM call that
reads/duplicates that state dereferences freed memory β UAF. Impact per the
finding: kernel-heap info leak (freed content surfaced to userspace via
property read / state duplication), with code-exec potential under slab
grooming.
Why it does NOT reproduce on this guest
- amdgpu_dm is part of the amdgpu driver, not in GENERIC.
nm /boot/kernel/kernel.debug | grep -ciE 'radeon|amdgpu'β 0; no amdgpu module is loaded. - No AMD GPU in the QEMU guest (serial-console VM, no PCI GPU). Even with the module loaded there is no DRM connector / CRTC / plane for amdgpu_dm to instantiate, so none of the three reset callbacks is ever invoked.
- Trigger requires sustained memory pressure during a DRM atomic commit/reset ioctl on an amdgpu-managed object. None of these preconditions are achievable on the QEMU guest.
Exploit chain
none β primitive (kernel UAF) requires amdgpu driver loaded + AMD hardware + memory pressure during a DRM ioctl. None are present on this guest.
PoC changes
none β no executable PoC is possible; the path is dead code in the running kernel and depends on hardware this guest does not have.
Recommended fix
Always assign NULL to the state pointer on the OOM path of each reset
function (mirroring the upstream linuxdrm helper contract which expects
the reset callback to leave *->state == NULL on failure). See
fix.diff β applies cleanly with git apply (validated). Matches the
finding markdown's proposal.
Fix verification
not_testablegit apply --check validated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. amdgpu_dm reset functions UAF on kzalloc OOM. amdgpu not in GENERIC.
No comments yet.