β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4566

VCN rings ship with zero CS ib validation β€” no .parse_cs hook, userspace decode messages (session handle, fb buffer addresses/sizes) reach firmware unvalidated

Summary

amdgpu_cs validates ib contents only for rings whose funcs set .parse_cs; every UVD and VCE ring in this tree carries one but none of the three VCN ring tables does (this snapshot predates upstream's amdgpu_vcn_cs_parse/amdgpu_vcn_dec_cs_msg backport). A render-node user on a Raven APU submits a VCN IB whose embedded decode message names an arbitrary session handle and fb_buffer addresses never checked against the CS bo list - buffers absent from the list are unpinned, so TTM eviction can relocate them mid-execution while firmware still DMAs through the stale GPUVA: racy cross-process VRAM corruption; malformed fields give a reliable GPU-hang DoS. Statically certain (grep-provable); no AMD GPU on guest. Backport-the-upstream-validation fix direction.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4566 Β· 5 files
FileTypeDescriptionSize
README.md β€” 1.2 KB ↓ raw
VERDICT.md β€” 4.5 KB ↓ raw
static_proof.txt β€” 3.9 KB view raw
verdict.json β€” 3.3 KB view raw
manifest.json β€” 944 B view raw

DF-4566 β€” VCN rings have zero CS ib validation (no .parse_cs hook)

What this is

A static, code-provable finding: every UVD and VCE ring in this DragonFly tree carries a kernel-side ib parser (.parse_cs), but none of the three VCN rings does. As a result, userspace-submitted VCN decode/encode/jpeg indirect buffers β€” including the firmware decode message with its session handle and frame-buffer (fb) address/size tables β€” reach the VCN firmware with no kernel validation whatsoever.

Build / Run

Not applicable β€” this is an absence-of-validation defect on AMD Raven (VCN) hardware. The audit QEMU guest runs X86_64_GENERIC with no AMD GPU and no /dev/dri (verified: ls /dev/dri β†’ No such file or directory), so a GPU command-submission PoC cannot be executed there. See VERDICT.md for the static proof and static_proof.txt for the raw excerpts.

Expected result (on real Raven hardware)

A render-node client submits a decode ib whose message references a buffer that is NOT in the CS bo list (or a session handle that was never created); upstream Linux rejects this in amdgpu_vcn_dec_cs_msg() β€” this tree accepts it silently and the firmware dereferences it.

VERDICT.md
↓ download raw

DF-4566 VERDICT β€” VCN rings ship without any CS ib parser

Status: untested (dynamically), certain (statically). Impact demonstrated: none (hardware absent); defect existence: proven by inspection.

What was verified and how

The audited file is sys/dev/drm/amd/amdgpu/amdgpu_vcn.c (905 LOC, pass 2). The pass-1 context expected a VCN decode-message parser (amdgpu_vcn_dec_cs_msg / amdgpu_vcn_cs_parse) to exist in this file. It does not exist anywhere in this tree β€” verified by rg -n "amdgpu_vcn_(cs_parse|dec_cs_msg)" sys/ β†’ no matches (see static_proof.txt). This snapshot is ~Linux-4.17/4.18-vintage amdgpu (VCN 1.0, Raven-only, sys/dev/drm/amd/amdgpu/amdgpu_vcn.c:65-76); upstream Linux added the VCN ib check (amdgpu_vcn_cs_parse / amdgpu_vcn_dec_cs_msg, wired as .parse_cs on the VCN dec ring) only in the ~5.1 era. The tree never got it.

Why this is a security gap, not just a missing feature

  1. amdgpu_cs.c:833-836 runs the whole "ib contents" path only when ring->funcs->parse_cs || ring->funcs->patch_cs_in_place (the code comment itself says "Only for UVD/VCE VM emulation"). All three VCN ring func tables β€” vcn_v1_0_dec_ring_vm_funcs (vcn_v1_0.c:2043-2069), vcn_v1_0_enc_ring_vm_funcs (2076-2101) and vcn_v1_0_jpeg_ring_vm_funcs (2103-2135) β€” set neither hook. Every UVD ring (uvd_v4_2.c:756, uvd_v5_0.c:865, uvd_v6_0.c:1530) and every VCE ring (vce_v2_0.c:615, vce_v3_0.c:902, vce_v4_0.c:1077) in the same tree does set one β€” the asymmetry is the defect.

  2. Consequence: a local user with render-node access on Raven APUs (0x1002:0x15dd / 0x15d8, amdgpu_drv.c:911-912) submits an AMDGPU_CHUNK_ID_IB targeting a VCN ring whose embedded decode message contains an arbitrary session handle and arbitrary fb-buffer addresses and sizes. Nothing checks that (a) the handle was created (cf. amdgpu_uvd.c session handling / DF-1657 family), or (b) each fb_buffer address corresponds to a GEM object in the validated CS bo list with adequate size (the job upstream's amdgpu_vcn_dec_cs_msg performs for H264/HEVC messages).

  3. Addressing model (severity limiter): unlike pre-VM UVD (DF-4404: physical addressing), VCN 1.0 runs the ib under the submitting VM's page tables β€” the dec ring programs mmUVD_LMI_RBC_IB_VMID with the submitter's vmid (vcn_v1_0.c:1372-1378; jpeg mmUVD_LMI_JPEG_VMID vcn_v1_0.c:1736-1741). So raw msg addresses can only name mappings the attacker already owns; the kernel-integrity angle is the bo-list/pinning divergence: buffers named in the message but absent from the CS bo list are not pinned/reserved for the job, so TTM may evict/relocate them while the firmware still DMAs through them β†’ cross-process VRAM corruption (racy), plus unaccounted session handles and trivial GPU-hang DoS. That is why this is Medium, not High.

Why not reproduced on the guest

The audit QEMU guest (DragonFly dfbsd 6.5-DEVELOPMENT ... X86_64_GENERIC, verified 2026-09-21) has no AMD GPU and no /dev/dri; amdgpu cannot even load, and no VCN ring exists to submit to. Building the PoC is therefore impossible on the available target β€” not a code-path refutation (the cited path is trivially reachable on any Raven APU with the amdgpu KMD bound).

Classification mapping

  • Defect existence: certain (grep-provable absence; ring-func tables cited).
  • PoC status per audit status set: untested (no hardware target exists in the harness; nothing was built or run).
  • Demonstrated impact: none (no runtime demonstration possible).

Backport upstream's VCN dec ib validation (amdgpu_vcn_cs_parse / amdgpu_vcn_dec_cs_msg, incl. its follow-up bounds fixes on the fb-buffer count for H264/HEVC messages) and wire .parse_cs = amdgpu_vcn_ring_parse_cs into vcn_v1_0_dec_ring_vm_funcs. A full parser backport is ~200 lines from upstream; it is not authored here because verification on real hardware was not possible, and per audit rules fix.diff accompanies reproduced memory-corruption findings.

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.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Fix validation impossible: no AMD GPU on the verification guest, and the bug itself was not reproduced at runtime (status untested). fix.diff intentionally not authored (audit rule: fix.diff accompanies reproduced memory-corruption findings).

VERDICT.md section 'Recommended fix'; guest runtime check in notes
per-fix-DF-4566

Confirmed kernel references

Detail

Exploit chain

on real Raven APU: open render node -> AMDGPU_CS with AMDGPU_CHUNK_ID_IB on VCN dec ring -> ib embeds crafted decode msg whose fb_buffer_address[] names a mapping absent from the CS bo list (or oversized vs bo) -> job runs without reservation/pinning -> TTM eviction relocates the buffer mid-exec -> firmware DMAs through stale GPUVA -> cross-process VRAM corruption (racy); unconditional variant: bogus session handle / msg fields -> firmware fault -> GPU hang (DoS). Not runnable on the QEMU guest (no AMD GPU).

Evidence (decisive lines)

static_proof.txt (rg output: parse_cs present on all uvd/vce rings, absent on all vcn rings; vcn_v1_0.c:2043-2069 ring funcs; amdgpu_cs.c:832-838 gate); VERDICT.md (full narrative incl. VM-addressing severity limiter, vcn_v1_0.c:1372-1378)

PoC changes

n/a β€” no PoC was seeded or run; finding is proven by code inspection (grep + ring func tables)

Verified recommended fix

Backport upstream amdgpu_vcn_cs_parse/amdgpu_vcn_dec_cs_msg (H264/HEVC message validation: session handle + fb_buffer address/size vs CS bo list) and set .parse_cs on vcn_v1_0_dec_ring_vm_funcs

Verdict

Statically proven: none of the three VCN ring func tables (vcn_v1_0.c:2043-2135) sets .parse_cs/.patch_cs_in_place, so amdgpu_cs.c:833-836 skips ib-contents validation entirely for VCN β€” userspace decode messages (session handle, fb buffer addresses/sizes) reach firmware unvalidated, unlike every UVD/VCE ring in the same tree. Dynamically untestable: the audit QEMU guest (X86_64_GENERIC) has no AMD GPU and no /dev/dri, so no PoC could be built or run; the defect is an absence provable by inspection, impact chain (bo-list pinning divergence -> cross-process VRAM corruption; session-handle spoofing; GPU hang) reasoned but not demonstrated.