Latent kfree() on embedded drm_framebuffer in amdgpufb_create error path (slab-corruption landmine)
- File:
sys/dev/drm/amd/amdgpu/amdgpu_fb.c - Lines: 255, 316
- Severity: Low
- CVSS 3.1:
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U:C:N/I:N/A:H - CWE: CWE-763 Release of Invalid Pointer or Pointer to Inconsistent Data
- Confidence: certain
- Status: new
- Related: DF-1970 (radeon_fb.c identical-class bug)
Summary
The error path at line 316 does kfree(fb) where fb = &rfbdev->rfb.base
(line 255) is an embedded struct inside the kzalloc'd amdgpu_fbdev,
not a separately allocated object. Calling kfree on an interior pointer
corrupts the kernel heap.
On DragonFly this path is currently unreachable with non-NULL fb (no
goto out after line 255), but the #else (Linux) path at line 293-296
does have a goto out reachable with fb set, making this a live bug on
non-DF builds and a dangerous landmine on DF.
Root cause
At line 255: fb = &rfbdev->rfb.base. The amdgpu_fbdev struct
(amdgpu_mode.h:316-321) embeds struct amdgpu_framebuffer rfb (line 318),
which in turn embeds struct drm_framebuffer base (amdgpu_mode.h:310).
So fb points to an interior offset of the kzalloc'd rfbdev allocation
(line 360 of amdgpu_fbdev_init).
The error path at line 312-317 does:
drm_framebuffer_cleanup(fb); // removes fb from DRM lists
kfree(fb); // frees from the WRONG offset
kfree() expects a pointer to the start of a slab/kmalloc allocation. Passing
an interior pointer (rfbdev->rfb.base, which is at a non-zero offset within
rfbdev) corrupts the slab allocator's metadata, leading to heap corruption,
double-free, or panic.
On DragonFly
The #ifdef __DragonFly__ block (lines 260-270) has no goto out after fb
is set at line 255 β it falls through to return 0 at line 306. So kfree(fb)
is unreachable with non-NULL fb on DF.
On Linux (the #else path, lines 271-297)
Line 293-296 has if (info->screen_base == NULL) { ret = -ENOSPC; goto out; }
which IS reachable with fb non-NULL. On Linux builds, this would be a
live heap corruption bug.
This code was clearly copied from a context where fb was separately
kzalloc'd (like amdgpu_display_user_framebuffer_create at
amdgpu_display.c:544 kzallocs amdgpu_fb) without adapting for the
embedded case. The radeon_fb.c equivalent (lines 327-332) has the identical
bug.
Threat model
On DragonFly: latent β any future code change that adds a goto out
after line 255 (e.g., a new error check in the DragonFly info-setup block)
would instantly make this a heap corruption primitive.
On Linux: live heap corruption when amdgpu_bo_kptr() returns NULL
(line 282/293), which can happen under memory pressure or on specific ASICs.
Impact: kernel heap corruption β potential code execution in ring 0, or immediate panic.
Proof of concept
On DragonFly: not directly triggerable (the goto out at line 295 is in the
#else block). The risk is that a maintainer adds an error check in the
#ifdef __DragonFly__ block (e.g., checking for NULL vaddr) and the existing
kfree(fb) becomes a heap corruption.
On Linux: trigger amdgpu_bo_kptr returning NULL by consuming system memory
before fbdev init, then kfree on the interior pointer corrupts the slab.
PoC sketch for the latent DF risk: apply a trivial one-line patch adding
if (!info->vaddr) { ret = -ENOMEM; goto out; } after line 270, then boot
with an amdgpu card β the first modeset triggers kfree on the embedded fb
β immediate panic.
Recommended fix
Remove the kfree(fb) entirely β fb is never separately allocated in this
function. The fix is included in the diff for DF-1982, which replaces the
entire error block with just if (gobj) amdgpufb_destroy_pinned_object(gobj);.
The framebuffer cleanup (drm_framebuffer_unregister_private /
drm_framebuffer_cleanup) is handled later by amdgpu_fbdev_destroy() when
obj[0] is set, or is unnecessary when obj[0] is NULL (framebuffer_init
failed).
References
sys/dev/drm/amd/amdgpu/amdgpu_fb.c:255βfb = &rfbdev->rfb.basesys/dev/drm/amd/amdgpu/amdgpu_fb.c:316β the latentkfree(fb)sys/dev/drm/amd/amdgpu/amdgpu_mode.h:310,316-321βfbis embedded insiderfbdevsys/dev/drm/amd/amdgpu/amdgpu_display.c:544β different code path wherekzalloc(amdgpu_fb)makes kfree valid
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1983 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | Source verification narrative | 1.1 KB | β raw |
| fix.diff | suggested-fix | Fix: Remove kfree(fb) from error path (fb is embedded, not separately allocated). | 335 B | view raw |
| build.sh | build-script | Build/validation instructions | 366 B | view raw |
| run.sh | run-script | Run instructions (HW-gated, source-only) | 184 B | view raw |
| env.txt | environment | Guest environment | 404 B | view raw |
DF-1983 - Source Verification
Verdict: REPRODUCED (source-only confirmation)
Finding: sys/dev/drm/amd/amdgpu/amdgpu_fb.c:316
Mechanism: amdgpufb_create error path kfree(fb) where fb is EMBEDDED inside rfbdev (not separate heap). Heap corruption. Latent on DragonFly (#else path not compiled).
Hardware dependency: Latent on DragonFly (#else non-DF path). Active on Linux builds.
Fix: Remove kfree(fb) from error path (fb is embedded, not separately allocated).
Verification method
Source-only confirmation. The cited code path was traced line-by-line in the audited sys/ tree. The bug exists exactly as described. This is a HW-gated driver finding β the vulnerable code path requires specific hardware (GPU, controller, PHY, TPM, etc.) not present in the QEMU audit guest. Runtime reproduction on this guest is not possible without the hardware.
Fix validation
fix.diff authored and applied to guest source. All 40 fixes in this batch
compile cleanly in a single combined kernel build: make -j6 nativekernel
KERNCONF=X86_64_GENERIC β rc=0, zero -Werror violations.
Kernel: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
Fix verification
not_testablenot_testable: HW-gated. fix.diff applies + compiles in batch build (rc=0 -Werror). Source trace confirms fix closes the path.
Batch build: 40 fix.diffs applied, make nativekernel β rc=0 -Werror. Bug at sys/dev/drm/amd/amdgpu/amdgpu_fb.c:316 source-confirmed.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- a
- m
- d
- /
- a
- m
- d
- g
- p
- u
- /
- a
- m
- d
- g
- p
- u
- _
- f
- b
- .
- c
- :
- 3
- 1
- 6
Detail
Exploit chain
none
Evidence (decisive lines)
Source trace sys/dev/drm/amd/amdgpu/amdgpu_fb.c:316. HW-gated (no HW in QEMU). Fix compiles in batch build rc=0.
PoC changes
Evidence pack: VERDICT.md, fix.diff, manifest.json. Fix: kfree(fb) on embedded struct β heap corruption. Remove kfree(fb).
Verified recommended fix
See fix.diff. kfree(fb) on embedded struct β heap corruption. Remove kfree(fb).
Verdict
REPRODUCED (source-only). sys/dev/drm/amd/amdgpu/amdgpu_fb.c:316: kfree(fb) on embedded struct β heap corruption. Remove kfree(fb).
No comments yet.