amdgpu_atomfirmware_allocate_fb_scratch: VBIOS-controlled unclamped kernel allocation (up to 64MB) whose -ENOMEM return the caller ignores β NULL-scratch write chain on Linux-semantics allocators, dead error branch on DragonFly
Summary
used_by_driver_in_kb (untrusted u16)<<10 drives an unclamped kzalloc; on failure the caller drops the return and unguarded consumers write at NULL+4 (atombios_dp.c:74-76) / memcpy from NULL (atombios_i2c.c:104). On DFly the branch is provably dead (M_WAITOK never NULL - failure instead panics with a VBIOS-influenced 64MB request); on Linux-semantics allocators it is a deterministic NULL-page write (upstream master still ignores the return - verified). File byte-identical to Linux v5.0. Clamp + propagate fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4980 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.4 KB | β raw | |
| VERDICT.md | β | 3.7 KB | β raw | |
| verdict.json | β | 3.0 KB | view raw | |
| fix.diff | β | 2.0 KB | view raw | |
| manifest.json | β | 1018 B | view raw |
DF-4980 β amdgpu_atomfirmware_allocate_fb_scratch: untrusted VBIOS-sized kernel
allocation whose error return the caller ignores
File: sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c (pass 2)
Severity: Info (defense-in-depth) Β· Bucket: base:dev Β· Status: untested
(no AMD GPU on the verification guest; Phase V not applicable for an Info finding)
What the code does
amdgpu_atomfirmware_allocate_fb_scratch()parses the VBIOSvram_usagebyfirmwaretable and takesused_by_driver_in_kb(u16, fully VBIOS-controlled) as the size of the ATOM interpreter scratch buffer:
sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:99usage_bytes = le16_to_cpu(firmware_usage->used_by_driver_in_kb) << 10;β up to 0xFFFF Γ 1024 = 67,107,840 bytes (64 MB), no clamp, no sanity bound.sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:106ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);:107-108if (!ctx->scratch) return -ENOMEM;
- The only caller drops the return value on the floor:
sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:2046amdgpu_atomfirmware_allocate_fb_scratch(adev);- (legacy twin, same defect:
amdgpu_atombios.c:2049βamdgpu_atombios_allocate_fb_scratch(adev);, impl at:1781)
- Unguarded consumers of
ctx->scratch(no NULL check, no size check):
sys/dev/drm/amd/amdgpu/atombios_dp.c:74-76base = (unsigned char *)(...->scratch + 1);amdgpu_atombios_copy_swap(base, send, send_bytes, true);β writesys/dev/drm/amd/amdgpu/atombios_i2c.c:54+:104base = (unsigned char *)...->scratch;β¦copy_swap(buf, base, num, false)β read
Impact analysis β why this is Info on DragonFly
- On Linux-semantics allocators (kzalloc returns NULL): allocation failure
β
-ENOMEMignored βctx->scratch == NULL,scratch_size_bytes == 0β next DP AUX / hw-I2C transaction writes to (NULL+4) / reads from NULL β kernel NULL-page fault panic. The interpreter itself is guarded (atom.c:273,atom.c:529checkscratch_size_bytes), so only the dp/i2c direct consumers fault. - On DragonFly:
GFP_KERNELmaps toM_WAITOK | M_CACHEALIGN(sys/dev/drm/include/linux/gfp.h:40) β noM_NULLOK. DFkmalloccannot return NULL for aM_WAITOKrequest; on kernel-map exhaustion the allocator itself panics (sys/kern/kern_slaballoc.c:1723-1724:panic("kmem_slab_alloc(): kernel_map ran out of space!")). Therefore:107-108is dead code on DF and the NULL-write chain cannot occur here. Residual DF exposure: a crafted VBIOS can force a 64 MBM_WAITOKkernel allocation at attach (or the allocator's panic under kernel-map pressure) β defense-in-depth only, no demonstrated unprivileged impact. - Upstream status: the whole file is byte-identical to Linux v5.0, and
upstream master still ignores the return
(
amdgpu_atombios.c:1935on master, checked 2026-09-25). The unclamped untrusted size is likewise unfixed upstream.
Fix
Authoritative diff: fix.diff β clamp the untrusted size to the
driver's own default (20 KB) and propagate the error from both branches of
amdgpu_atombios_init().
Why no guest run
Info-grade finding; the DF verification guest has no AMD GPU (no amdgpu device attaches), and on DF the defective branch is provably dead (M_WAITOK semantics above). Nothing to build or run β analysis-only evidence.
DF-4980 VERDICT
Status: untested Β· Impact: none (on DragonFly) Β· Confidence: likely (certainty of the code defect is high β the line-by-line chain is proven below; "likely" reflects that the exploitable manifestation requires Linux-allocator semantics or DF kernel-map exhaustion).
The defect (proven from source)
amdgpu_atomfirmware_allocate_fb_scratch() sizes a kernel allocation from an
untrusted VBIOS field and returns -ENOMEM on failure
(sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:99,106-108); the sole caller
ignores the return (sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:2046), and two
consumers use atom_context->scratch without any NULL guard
(sys/dev/drm/amd/amdgpu/atombios_dp.c:74-76 β write via copy_swap to
scratch + 1; sys/dev/drm/amd/amdgpu/atombios_i2c.c:54,104 β read). The
legacy twin has the identical shape (amdgpu_atombios.c:1781-1822,
ignored at :2049) and is the reachable instance on classic ASICs
(dce8/10/11 use atombios_dp/atombios_i2c by default).
Why the impact ceiling on DragonFly is "none"
kzalloc(size, GFP_KERNEL)βkmalloc(size, M_DRM, M_WAITOK|M_CACHEALIGN|M_ZERO)(sys/dev/drm/include/linux/slab.h:35,sys/dev/drm/include/linux/gfp.h:40). DFM_WAITOKwithoutM_NULLOKnever yields NULL β failure panics inside the allocator (sys/kern/kern_slaballoc.c:1721-1727). Soif (!ctx->scratch)atamdgpu_atomfirmware.c:107is dead code on DF; the NULL+4 write chain (real on Linux) cannot execute here.- The atom-interpreter FB paths are guarded by
scratch_size_bytes(sys/dev/drm/amd/amdgpu/atom.c:273-278,529-533), so no interpreter path derefs the buffer unguarded. - On the atomfw (Vega10+) path the unguarded dp/i2c consumers are not wired in this tree (no dce12 classic CRTC file exists; Vega10 classic falls back to dce_virtual which creates no DP/hw-I2C connectors; DC uses its own AUX). The reachable instance is the legacy twin on dce8/10/11 ASICs.
- Residual DF exposure: crafted VBIOS
used_by_driver_in_kb = 0xFFFFforces a 64 MBM_WAITOKallocation at attach β succeeds on a healthy system, panics viakmem_slab_alloconly under kernel-map exhaustion, or blocks indefinitely under memory pressure. Defense-in-depth fix warranted, no demonstrated unprivileged trigger.
Reproduction
Not applicable: the DF verification guest has no AMD GPU (amdgpu never
attaches), and the defective branch is provably dead on DF (point 1). A Linux
reproduction would be: classic ASIC (e.g. polaris), fail the kzalloc (fault
injection / memory pressure), hotplug a DP monitor β panic at
amdgpu_atombios_copy_swap writing to (NULL+4).
Fix validation
fix_status: not_testable β fix.diff clamps the untrusted size to the
driver's own 20 KB default and propagates the error from both branches of
amdgpu_atombios_init(). No kernel-build validation was performed (Info
finding, no guest amdgpu device; the change is error-plumbing only and cannot
be exercised on the guest).
Cross-references
- DF-2027 (pass 1, same file): all table parsers deref unvalidated
bios + data_offsetβ the offset OOB class. This finding is the ignored-error / untrusted-size class, distinct and not a re-report. - DF-4884/DF-4885: amdgpu_bios double-free + off-by-one (context).
- Upstream: file byte-identical to Linux v5.0; master still ignores the return (amdgpu_atombios.c:1935 as of 2026-09-25).
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.
Fix verification
not_testableFix validation not applicable: Info-grade finding with no reproducible impact on the verification guest (no AMD GPU; DF allocator semantics make the NULL branch dead). fix.diff is error-propagation + untrusted-size clamping authored from line-accurate source reading, never applied to sys/.
findings/poc/DF-4980/fix.diff
Confirmed kernel references
- sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:99
- sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:106
- sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:107
- sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:2046
- sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:2049
- sys/dev/drm/amd/amdgpu/atombios_dp.c:74
- sys/dev/drm/amd/amdgpu/atombios_i2c.c:104
- sys/dev/drm/include/linux/gfp.h:40
- sys/kern/kern_slaballoc.c:1723
Detail
Evidence (decisive lines)
findings/poc/DF-4980/VERDICT.md (line-proven chain) + README.md; decisive lines: amdgpu_atomfirmware.c:99,106-108; amdgpu_atombios.c:2046,2049; atombios_dp.c:74-76; atombios_i2c.c:54,104; gfp.h:40; slab.h:35; kern_slaballoc.c:1721-1727
PoC changes
n/a β analysis-only evidence pack; no PoC built (guest has no AMD GPU; the defective branch is provably dead on DF because GFP_KERNEL == M_WAITOK without M_NULLOK)
Verified recommended fix
Clamp the untrusted usage_bytes to the driver's own 20 KB default and check the return value of both allocate_fb_scratch variants in amdgpu_atombios_init()
Verdict
amdgpu_atomfirmware_allocate_fb_scratch() sizes kzalloc(GFP_KERNEL) from the untrusted VBIOS field used_by_driver_in_kb (up to 64 MB, unclamped) and its -ENOMEM return is ignored by the only caller (amdgpu_atombios.c:2046; legacy twin :2049), leaving consumers that dereference atom_context->scratch without any NULL guard (atombios_dp.c:74-76 write to scratch+1, atombios_i2c.c:54/104). On Linux-semantics allocators that failure is a NULL-page write panic; on DragonFly GFP_KERNEL maps to M_WAITOK without M_NULLOK (gfp.h:40) so kzalloc can never return NULL and the !ctx->scratch branch (amdgpu_atomfirmware.c:107) is dead code β failure instead surfaces as the allocator's own panic under kernel-map exhaustion with a VBIOS-influenced 64 MB request. Info/defense-in-depth: no demonstrated unprivileged impact on DF; unfixed upstream (master amdgpu_atombios.c:1935 still ignores the return).
No comments yet.