amdgpu_virt_init_data_exchange: host-controlled pf2vf_size drives a 1 KB memset (and the header reads) past the kmap'ed fw VRAM reservation β no validation that the region contains the 64 KB-offset exchange area
Summary
The reservation size comes verbatim from the host-controlled vBIOS (can be as small as 1KB) while the exchange area is hardcoded at +64KB: the header reads and the 1KB vf2pf memset at va+64K+pf2vf_size run up to ~69KB into a region that may be 1KB deep - OOB write (zeros, host-chosen offset) + OOB reads at init and post-FLR. Inherited from upstream v4.19; host-fed trigger (Low per the host-fed-mailbox precedent). Gate-on-region-size fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4916 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.7 KB | β raw | |
| VERDICT.md | β | 4.9 KB | β raw | |
| trigger.md | β | 1.2 KB | β raw | |
| env.txt | β | 178 B | view raw | |
| verdict.json | β | 3.4 KB | view raw | |
| manifest.json | β | 1.1 KB | view raw |
DF-4916 β amdgpu_virt_init_data_exchange: host-controlled pf2vf_size drives a 1 KB memset past the kmap'ed fw VRAM reservation (no region-bounds validation)
Build / Run / Expected
No runnable PoC on this guest β requires an SR-IOV VF AMD GPU guest whose host/PF (or vBIOS) supplies the pf2vf message. On real hardware:
- Boot a DragonFly SR-IOV VF guest whose vBIOS
VRAM_UsageByFirmwaretable declares the SR-IOV message reservation (ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION) withused_by_firmware_in_kbsmall, e.g. 4 (βfw_vram_usage.size = 4096), and whose GIM/PF writes a pf2vf header at VRAM offset 64 KB withsize β (0,4096)and a matching checksum (the key is host-known: on AI it is literally read out of mailbox 2,mxgpu_ai.c:176-180). kldload amdgpuin the guest.- Expected:
amdgpu_virt_init_data_exchange()runs at the end of device init (amdgpu_device.c:1695) and after VF FLR re-init (amdgpu_device.c:3345): - reads atfw_vram_usage.va + 65536are already past the 4 KB mapping (amdgpu_virt.c:402-408), - on checksum match,p_vf2pf = p_pf2vf + pf2vf_sizeandmemset(p_vf2pf, 0, 1024)(amdgpu_virt.c:416-420) writes up to offset 65536+4095+1024 β 69 KB into the 4 KB mapping β kernel OOB access on the VRAM kmap β guest panic (or silent VRAM corruption of whatever is mapped next).
Success criterion: panic (or dmesg evidence of the OOB) at driver init.
Files in this pack
VERDICT.mdβ full bound-math narrative with path:line citations.trigger.mdβ the host-side setup above.env.txtβ guest hardware inventory (no AMD GPU present).manifest.json,verdict.jsonβ machine records.
DF-4916 β VERDICT
Status: not_reproduced (hardware-gated β no AMD GPU / SR-IOV VF in the audit guest). The bounds defect itself is certain from source; the trigger data is host/PF-supplied, so guest-side reproduction requires SR-IOV hardware.
The chain, with the numbers
- The size of the firmware VRAM reservation is taken verbatim from the
vBIOS (in an SR-IOV guest the vBIOS is host-supplied):
amdgpu_atombios.c:1803-1807andamdgpu_atomfirmware.c:91-95setadev->fw_vram_usage.size = used_by_firmware_in_kb << 10. The only constraint anywhere issize > 0 && size <= visible_vram_size(amdgpu_ttm.c:1707-1708). No minimum size is enforced. amdgpu_ttm_fw_reserve_vram_init()(amdgpu_ttm.c:1742-1743) kmap's exactlyfw_vram_usage.sizebytes intofw_vram_usage.va.amdgpu_virt_init_data_exchange()(amdgpu_virt.c:392-443) β called atamdgpu_device.c:1695(end of device init on VF) andamdgpu_device.c:3345(post-FLR re-init) β hardcodesp_pf2vf = fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSETwithAMDGIM_DATAEXCHANGE_OFFSET = 64 * 1024(amdgpu_virt.h:74), and immediately dereferences it (header.size,header.version, version-dispatchedchecksum/feature_flagsreads viaAMDGPU_FW_VRAM_PF2VF_READ,amdgpu_virt.h:225-235) with no check that the reservation is even 64 KB deep. With a small-but-nonzero reservation every one of these reads is out of bounds of the kmap.pf2vf_size(u32 read from VRAM, fully host-written) is gated only by0 < pf2vf_size < 4096(amdgpu_virt.c:411) and a checksum whose key is host-supplied (AI: mailbox 2,mxgpu_ai.c:176-180; VI:checksum_keystays 0 β never initialized by mxgpu_vi). The gate therefore binds nothing against the actual reservation size.- On "checksum ok":
p_vf2pf = p_pf2vf + pf2vf_size(amdgpu_virt.c:416-418) andmemset(p_vf2pf, 0, sizeof(amdgim_vf2pf_info))(amdgpu_virt.c:419-420).sizeof(amdgim_vf2pf_info)= 1024 (v2 struct is padded to 256 u32s byAMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 64, 0, 14, 0),amdgpu_virt.h:209). Worst case the memset spans[va+65536+1, va+65536+4095+1024)β i.e. up to ~69 KB into a region the vBIOS may have declared as small as 1 KB.
So the guest kernel performs an OOB write (zeroes, 1 KB, host-chosen offset in (64 KB, 68 KB)) and OOB reads on the kmap'ed VRAM BO, purely on host-fed data. Behavior on x86-64 with an ioremap'ed TTM BO: access beyond the mapping either hits adjacent device memory (silent corruption) or an unmapped page (kernel page-fault panic). Guest userspace cannot reach this path (device-init time, root/host-controlled inputs).
This is an inherited upstream defect (Linux v4.19 has the identical code;
verified against torvalds/linux v4.19 amdgpu_virt.c lines 396-436), not a
port-introduced one β but it is a real robustness hole in the guest-kernel
trust boundary the file exists to implement.
Why not reproduced on the audit guest
No AMD PCI device exists in the QEMU guest (env.txt); amdgpu.ko never
binds; fw_vram_usage.va stays NULL and amdgpu_virt_init_data_exchange
returns at line 402. Hardware-gated β not_reproduced on this guest, impact
none here; the bound-math defect is certain.
Exploit chain
None from guest userspace. From a malicious/compromised host position: guest panic (init-time DoS) or 1 KB zero-corruption at a ~4 KB-wide host-chosen offset past a known kmap. No guest-privileged code-exec primitive identified.
Recommended fix
Validate the reservation actually contains the exchange area before any dereference, e.g.:
--- a/sys/dev/drm/amd/amdgpu/amdgpu_virt.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_virt.c
@@ -399,7 +399,14 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
adev->virt.fw_reserve.p_vf2pf = NULL;
- if (adev->fw_vram_usage.va != NULL) {
+ if (adev->fw_vram_usage.va != NULL &&
+ adev->fw_vram_usage.size >=
+ AMDGIM_DATAEXCHANGE_OFFSET + sizeof(amdgim_vf2pf_info)) {
adev->virt.fw_reserve.p_pf2vf =
(struct amdgim_pf2vf_info_header *)(
adev->fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSET);
plus, inside the pf2vf_size gate:
- if (pf2vf_size > 0 && pf2vf_size < 4096) {
+ if (pf2vf_size >= sizeof(struct amdgim_pf2vf_info_v2) &&
+ pf2vf_size + sizeof(amdgim_vf2pf_info) <=
+ adev->fw_vram_usage.size - AMDGIM_DATAEXCHANGE_OFFSET) {
(Upstream later grew equivalent guards; this mirrors them.)
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.)
DF-4916 β trigger procedure (SR-IOV VF host + guest)
Host side (PF, GIM/amdgpu or vendor stack):
- Program the VF's vBIOS
VRAM_UsageByFirmwaretable entry with theATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATIONflag andused_by_firmware_in_kb = 4(reservation of 4 KB β smaller than the 64 KBAMDGIM_DATAEXCHANGE_OFFSETthe guest driver assumes). - At VF setup, write a pf2vf header at VRAM + 64 KB with
version = 1 or 2,size = 0x1000 - 1(4095), a benignfeature_flags, and a correctchecksumoversizebytes (key: mailbox-2 value on AI, 0 on VI).
Guest side:
kldload amdgpu
At the tail of amdgpu_device_init (amdgpu_device.c:1695) the guest reads
the pf2vf header past the end of its 4 KB kmap and, on checksum match,
memsets 1024 bytes at va + 64 KB + 4095 β outside the reservation.
Expected observable: guest kernel page-fault panic at amdgpu_virt.c:419
(memset) or at the header reads (amdgpu_virt.c:406-408); with a larger
reservation merely corrupted VRAM contents.
Not runnable in the audit guest: no AMD GPU (env.txt). Amdgpu never binds,
fw_vram_usage.va == NULL, function returns at amdgpu_virt.c:402.
Fix verification
not_testableFix could not be validated: no SR-IOV AMD hardware in the audit guest, so neither baseline nor patched behavior is reachable.
VERDICT.md 'Recommended fix' section contains the git-apply-able diff against amdgpu_virt.c.
Confirmed kernel references
- sys/dev/drm/amd/amdgpu/amdgpu_virt.c:402
- sys/dev/drm/amd/amdgpu/amdgpu_virt.c:405
- sys/dev/drm/amd/amdgpu/amdgpu_virt.c:411
- sys/dev/drm/amd/amdgpu/amdgpu_virt.c:416
- sys/dev/drm/amd/amdgpu/amdgpu_virt.c:419
- sys/dev/drm/amd/amdgpu/amdgpu_virt.h:74
- sys/dev/drm/amd/amdgpu/amdgpu_virt.h:209
- sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:1805
- sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c:93
- sys/dev/drm/amd/amdgpu/amdgpu_ttm.c:1707
- sys/dev/drm/amd/amdgpu/amdgpu_device.c:1695
- sys/dev/drm/amd/amdgpu/amdgpu_device.c:3345
Detail
Evidence (decisive lines)
VERDICT.md (full bound math with path:line); trigger.md (host-side vBIOS/GIM setup); env.txt (guest pciconf: zero AMD devices)
PoC changes
No runnable PoC for this guest; pack carries the host-side trigger procedure (malicious/mismatched vBIOS reservation + forged pf2vf checksum) and source-level proof.
Verified recommended fix
Gate the whole exchange on fw_vram_usage.size >= AMDGIM_DATAEXCHANGE_OFFSET + sizeof(amdgim_vf2pf_info) and validate pf2vf_size >= sizeof(struct amdgim_pf2vf_info_v2) and pf2vf_size + sizeof(amdgim_vf2pf_info) <= size - AMDGIM_DATAEXCHANGE_OFFSET before use (see VERDICT.md diff).
Verdict
amdgpu_virt_init_data_exchange (amdgpu_virt.c:392-443) never validates that the kmap'ed fw VRAM reservation (fw_vram_usage.size taken verbatim from the host-supplied vBIOS, amdgpu_atombios.c:1803-1807 / amdgpu_atomfirmware.c:91-95; only gate is size>0 at amdgpu_ttm.c:1707) actually contains the fixed 64KB AMDGIM_DATAEXCHANGE_OFFSET exchange area. It dereferences va+64KB immediately (amdgpu_virt.c:402-408) and, on a host-forgeable checksum (key is host-supplied via mailbox 2, mxgpu_ai.c:176-180), memsets 1024 bytes at va+64KB+pf2vf_size with pf2vf_size host-controlled in (0,4096) (amdgpu_virt.c:411-420) - an OOB write of up to ~69KB offset into a region that may be as small as 1KB, plus OOB header reads. Guest panic or VRAM corruption at driver init / after VF FLR. Not reproduced on the audit guest (no AMD PCI device; fw_vram_usage.va stays NULL and the function returns at line 402). Bounds defect certain from source; inherited unchanged from upstream Linux v4.19.
No comments yet.