# 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

1. `amdgpu_atomfirmware_allocate_fb_scratch()` parses the VBIOS
   `vram_usagebyfirmware` table and takes `used_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:99`
     `usage_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:106`
     `ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);`
   - `:107-108` `if (!ctx->scratch) return -ENOMEM;`

2. The **only** caller drops the return value on the floor:

   - `sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:2046`
     `amdgpu_atomfirmware_allocate_fb_scratch(adev);`
   - (legacy twin, same defect: `amdgpu_atombios.c:2049` →
     `amdgpu_atombios_allocate_fb_scratch(adev);`, impl at `:1781`)

3. Unguarded consumers of `ctx->scratch` (no NULL check, no size check):

   - `sys/dev/drm/amd/amdgpu/atombios_dp.c:74-76`
     `base = (unsigned char *)(...->scratch + 1);`
     `amdgpu_atombios_copy_swap(base, send, send_bytes, true);`  ← write
   - `sys/dev/drm/amd/amdgpu/atombios_i2c.c:54` + `:104`
     `base = (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
  → `-ENOMEM` ignored → `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:529` check `scratch_size_bytes`), so only the
  dp/i2c direct consumers fault.
* **On DragonFly**: `GFP_KERNEL` maps to `M_WAITOK | M_CACHEALIGN`
  (`sys/dev/drm/include/linux/gfp.h:40`) — no `M_NULLOK`. DF `kmalloc` cannot
  return NULL for a `M_WAITOK` request; 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-108` is **dead code on DF** and the NULL-write chain cannot
  occur here. Residual DF exposure: a crafted VBIOS can force a 64 MB
  `M_WAITOK` kernel 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:1935` on master, checked 2026-09-25). The unclamped
  untrusted size is likewise unfixed upstream.

## Fix

Authoritative diff: [`fix.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.
