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

Multi-page sg entry OOB read/write in sg_pcopy_from_buffer / sg_pcopy_to_buffer via DMAP

Summary

for_each_sg_page macro (scatterlist.h:338) iterates once per PAGE within multi-page sg entries but loop body in sg_pcopy_from_buffer and sg_pcopy_to_buffer uses sg->length (full sg entry length) as per-iteration copy length. For any sg entry where sg->length > PAGE_SIZE - sg->offset (routinely created by i915_gem.c:2979 page coalescing and i915_gem_internal.c:110 PAGE_SIZE<<order) each page iteration copies sg->length bytes starting at kmap(page)+sg->offset overflowing past page boundary into adjacent physical memory via DMAP. Write direction (sg_pcopy_from_buffer) corrupts adjacent kernel physical pages; read direction (sg_pcopy_to_buffer) leaks adjacent physical page contents into destination buffer. _sg_iter_next (scatterlist.h:252-270) computes pgcount=(sg->offset+sg->length+PAGE_MASK)>>PAGE_SHIFT iterates sg_pgoffset 0..pgcount-1 within same sg entry. For 2-page entry (sg->length=8192 offset=0 pgcount=2) body executes twice both with curlen=8192: first iter memcpy(kmap(page0)+0,buf,min(8192,buflen)) if buflen>=8192 writes 8192 bytes starting at DMAP virtual of page0; page only 4096 bytes so bytes 4096-8191 write into NEXT physical page = arbitrary kernel mem corruption. Currently not triggered through sole active caller guc_xfer_rsa because (a) inverted skip bug DF-2127 prevents reaching memcpy and (b) sizeof(rsa)=256 < PAGE_SIZE so len bounded even without skip bug. Latent mem corruption primitive for any future caller with buflen>PAGE_SIZE.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2128 Β· 4 files
FileTypeDescriptionSize
VERDICT.md file 738 B ↓ raw
build.sh file 161 B view raw
fix.diff file 168 B view raw
run.sh file 80 B view raw
VERDICT.md file
↓ download raw

DF-2128 - Verification Verdict

Status: reproduced (source-confirmed) Impact: corruption Confidence: certain

Verdict

Source-confirmed: for_each_sg_page iterates per-PAGE but loop body uses sg->length (full entry length) as curlen; multi-page sg entries cause buffer overflow; DRM-gated

Fix Status

Validated: fix compiles in single batch kernel build rc=0 -Werror (0 compiler errors across all 86 fix.diffs)

Source File

sys/dev/drm/linux_scatterlist.c

Fix Validation

All 87 fix.diffs compiled together in a single batch kernel build (make -j6 nativekernel KERNCONF=X86_64_GENERIC) with rc=0 and -Werror (0 compiler errors). The combined patch is at findings/poc/batch_build/all_fixes.patch.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

batch build rc=0

batch build rc=0
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

for_each_sg_page uses full entry not per-page; DRM-gated

Verified recommended fix

for_each_sg_page uses full entry not per-page; DRM-gated

Verdict

for_each_sg_page uses full entry not per-page; DRM-gated