vf2pf checksum computed over pf2vf_size bytes instead of sizeof(amdgim_vf2pf_info): out-of-bounds read of up to ~3 KB past the 1 KB vf2pf struct and a wrong protocol checksum published to the host
Summary
Copy-paste of the host-controlled pf2vf length into the vf2pf checksum call: the byte-sum reads up to 4095 bytes from a 1024-byte object (~3KB past, potentially off the kmap), and the host receives a checksum over the wrong range so a conformant PF silently rejects the guest's vf2pf message (telemetry exchange broken on benign hosts). Inherited verbatim from upstream. One-line length fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4917 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.4 KB | β raw | |
| VERDICT.md | β | 3.1 KB | β raw | |
| trigger.md | β | 768 B | β raw | |
| env.txt | β | 178 B | view raw | |
| verdict.json | β | 2.7 KB | view raw | |
| manifest.json | β | 975 B | view raw |
DF-4917 β vf2pf checksum computed with pf2vf_size instead of sizeof(amdgim_vf2pf_info): OOB read past the 1 KB vf2pf struct + broken protocol checksum
Build / Run / Expected
Same hardware preconditions as DF-4916 (SR-IOV VF AMD GPU guest, host-fed pf2vf message). On real hardware:
- Host writes a pf2vf message with
size = 4095and a valid checksum. - Guest
kldload amdgpuβamdgpu_virt_init_data_exchange()zeroesp_vf2pf(1 KB), fills header/driver_version/driver_cert, then computes the vf2pf checksum overpf2vf_size(4095) bytes starting atp_vf2pf(amdgpu_virt.c:435-439) instead of over the 1 KB struct. - Expected: the byte-sum loop (
amdgpu_virt.c:383-384) walks ~3 KB past the end ofamdgim_vf2pf_infoβ past the end of the exchange area and, with a tight reservation, past the kmap (OOB read of device memory); and the checksum the host receives covers the wrong byte range, so a spec-conformant PF/GIM rejects the vf2pf message (telemetry/features exchange silently broken even on benign hosts).
Success criterion: dmesg-visible GIM-side checksum mismatch, or OOB
read fault with a tight reservation.
Files in this pack
VERDICT.mdβ narrative + upstream comparison.trigger.mdβ host-side setup.env.txtβ guest hardware inventory (no AMD GPU present).manifest.json,verdict.jsonβ machine records.
DF-4917 β VERDICT
Status: not_reproduced (hardware-gated β no AMD GPU / SR-IOV VF in the audit guest). The defect is certain from source and confirmed identical in upstream Linux v4.19 (inherited, not port-introduced).
The defect
amdgpu_virt.c:435-439:
AMDGPU_FW_VRAM_VF2PF_WRITE(adev, checksum,
amdgpu_virt_fw_reserve_get_checksum(
adev->virt.fw_reserve.p_vf2pf,
pf2vf_size, /* <-- wrong */
adev->virt.fw_reserve.checksum_key, 0));
The object being checksummed is the vf2pf message just written at
p_vf2pf, whose size is sizeof(amdgim_vf2pf_info) β the same value the
code itself wrote into the vf2pf header two statements earlier
(amdgpu_virt.c:423-424). Instead the length passed is pf2vf_size β the
pf2vf message's host-controlled length β (0, 4096) (amdgpu_virt.c:411).
Consequences:
- OOB read: the sum loop at
amdgpu_virt.c:383-384readspf2vf_sizebytes fromp_vf2pf. Withpf2vf_sizeup to 4095 and a 1024-byte struct, up to ~3 KB past the end of the vf2pf area is read. The exchange area ends atp_pf2vf + pf2vf_size + 1024; the read ends atp_pf2pf + 2*pf2vf_size, which exceeds it bypf2vf_size - 1024bytes. Combined with DF-4916's missing region check this can walk off the kmap; with a generous reservation it silently reads unrelated VRAM. - Wrong checksum: the value published to the host covers
key + N garbage bytes β 0, not the vf2pf message, so any consumer that verifies per the GIM protocol discards the guest's message β breaking the feature-flag/error-log exchange (adev->virt.gim_featureconsumers) on otherwise healthy hosts.
Upstream comparison: Linux v4.19 drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
line 429-433 passes pf2vf_size identically β the bug was inherited from the
vanilla source this tree ported (verbatim diff archived in the analysis; the
same lines existing in DF at amdgpu_virt.c:435-439).
Why not reproduced on the audit guest
No AMD PCI device in the guest (env.txt); the function is unreachable
(fw_vram_usage.va == NULL). Hardware-gated β not_reproduced here; the
source-level defect is certain.
Exploit chain
None β host-visible protocol corruption + bounded OOB read of VRAM adjacent to the exchange area. No guest-privileged primitive.
Recommended fix
--- a/sys/dev/drm/amd/amdgpu/amdgpu_virt.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_virt.c
@@ -435,7 +435,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
AMDGPU_FW_VRAM_VF2PF_WRITE(adev, checksum,
amdgpu_virt_fw_reserve_get_checksum(
adev->virt.fw_reserve.p_vf2pf,
- pf2vf_size,
+ sizeof(amdgim_vf2pf_info),
adev->virt.fw_reserve.checksum_key, 0));
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-4917 β trigger procedure (SR-IOV VF host + guest)
Host side: write a pf2vf message with size = 4095, version = 2, correct
checksum (key = mailbox-2 value on AI, 0 on VI).
Guest side:
kldload amdgpu
amdgpu_virt_init_data_exchange then computes the vf2pf checksum over 4095
bytes starting at p_vf2pf (amdgpu_virt.c:435-439), reading ~3 KB past the
1024-byte amdgim_vf2pf_info struct (amdgpu_virt.h:181-210).
Expected observable:
- benign host with large reservation: GIM rejects the vf2pf message
(checksum mismatch) β silent telemetry break;
- host with tight reservation (see DF-4916 setup): kernel page-fault at the
byte-sum loop amdgpu_virt.c:383-384.
Not runnable in the audit guest: no AMD GPU (env.txt); path unreachable.
Fix verification
not_testableFix could not be validated: no SR-IOV AMD hardware in the audit guest; the one-line diff restores the intended length trivially.
VERDICT.md 'Recommended fix' section contains the git-apply-able diff against amdgpu_virt.c.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (length math + upstream comparison); trigger.md (host-side setup); env.txt (guest pciconf: zero AMD devices)
PoC changes
No runnable PoC for this guest; pack carries the host-side trigger procedure and source-level proof.
Verified recommended fix
Pass sizeof(amdgim_vf2pf_info) instead of pf2vf_size to amdgpu_virt_fw_reserve_get_checksum at amdgpu_virt.c:438 (see VERDICT.md diff).
Verdict
amdgpu_virt.c:435-439 computes the vf2pf message checksum with length pf2vf_size (host-controlled, (0,4096)) instead of sizeof(amdgim_vf2pf_info) (1024). The byte-sum loop (amdgpu_virt.c:383-384) then reads up to ~3KB past the 1KB vf2pf struct - past the exchange area and, with a tight reservation, off the kmap - and the checksum published to the host covers the wrong byte range so spec-conformant PFs reject the guest's message (silent telemetry/feature-flag breakage on benign hosts). Inherited verbatim from upstream Linux v4.19 (verified against torvalds/linux). Not reproduced on the audit guest: no AMD PCI device, fw_vram_usage.va == NULL, function returns at amdgpu_virt.c:402. Source-level defect certain.
No comments yet.