DF-5227 / verdict.json
{ "finding_id": "DF-5227", "status": "reproduced", "verdict": "REPRODUCED on stock drm.ko (DragonFly 6.5-DEVELOPMENT guest): dma_alloc_coherent() (sys/dev/drm/linux_dma.c:47) implements the Linux coherent-allocation API over kmem_alloc_contig() without M_ZERO (vm_contig.c:612 passes M_NOWAIT only; zeroing requires M_ZERO at vm_contig.c:533-534; reserve path vm_contig.c:288 never zeroes), so the returned buffer contains the previous owners kernel memory verbatim. PoC: contigmalloc 2MB -> marker fill -> contigfree -> dma_alloc_coherent 2MB lands on the SAME physical block (0x3000000) with 512/512 stale pages and the marker readable in the allocation. Contract violation certain; live in-tree callers (amdgpu_ih.c:66, drm_pci.c:130, radeon_gart.c:85) all carry manual memset() workarounds, so no unprivileged leak on stock desktop today -> severity Medium (latent kernel info leak for any caller that trusts the API, e.g. future upstream syncs). Fix validated in the same run: contigmalloc_map with M_NOWAIT|M_ZERO returns a fully zeroed buffer (marker_hits=0/512 stale 0/512) with identical reuse determinism.", "reproduced": true, "impact": "leak", "confidence": "certain", "exploit_chain": "spray/stale kernel data in contiguous physical pages (any prior contigmalloc/kmem_alloc_contig user, incl. network driver rings or a previous coherent allocation) -> driver calls dma_alloc_coherent() trusting the zeroing contract -> GPU/engine reads the buffer -> userspace reads GPU-accessible memory: stale kernel memory disclosure. The in-kernel primitive (stale bytes verbatim in the coherent allocation) is demonstrated; the userspace-read leg requires GPU hardware (absent on the audit guest).", "evidence": "run.log: SAME PHYSICAL BLOCK, marker_hits=512 stale_nonzero_pages=512/512, hexdump lines DF5227 LEAK 0000: 44 46 35 32 32 37 ... |DF5227-STALE-Ker|; run.fixed.log: marker_hits=0 stale_nonzero_pages=0/512", "kernel_refs": [ "sys/dev/drm/linux_dma.c:47", "sys/dev/drm/linux_dma.c:64", "sys/vm/vm_contig.c:612", "sys/vm/vm_contig.c:533", "sys/vm/vm_contig.c:288", "sys/dev/drm/amdgpu/amdgpu_ih.c:66", "sys/dev/drm/drm_pci.c:130", "sys/dev/drm/radeon/radeon_gart.c:85" ], "poc_changes": "Authored fresh (no usable seed for this finding; the reserved DF-5226 directory holds the twin-batchs unrelated refuted-candidate negative record and was left untouched, so this finding used the next reserved ID). KLD module calls the real drm.ko-exported dma_alloc_coherent; determinism engineered via the DMA-reserve first-fit alist reuse (contigmalloc/memset/contigfree immediately before the coherent alloc).", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 240, "guest_dirty": 0, "build_cmd": "cd /tmp/poc/DF-5227 && make", "run_cmd": "kldload drm; kldload /tmp/poc/DF-5227/poc5227.ko; dmesg | grep DF5227", "code_hash": "40fbf2c18620bd11c034f7e1fccdb31daba8e1feba2784698fe3aaeba3a91203", "notes": "Fix shared with DF-5228 (same two functions rewritten to contigmalloc_map(M_ZERO)/contigfree). Observation kept for the record: kldunload drm (no device attached) hung the guest linker subsystem once - pre-existing drm teardown behavior (DF-4532/DF-5064 family), unrelated to this patch. Guest reset clean (vm.sh reset with-src) after evidence collection.", "recommended_fix": "Implement dma_alloc_coherent with contigmalloc_map(..., M_NOWAIT | M_ZERO, ...) instead of kmem_alloc_contig (and dma_free_coherent with contigfree - see DF-5228); fix.diff in this pack.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff applied to guest /usr/src/sys/dev/drm/linux_dma.c, drm.ko rebuilt from source and loaded on a fresh boot (vm.sh reset with-src): the identical PoC returns marker_hits=0 stale_nonzero_pages=0/512 (run.fixed.log) - the stale-memory primitive is gone; allocation still succeeds on the same physical block, so no functional regression in the PoC path.", "fix_evidence": "run.fixed.log: DF5227 RESULT: marker_hits=0 stale_nonzero_pages=0/512; compare run.log baseline marker_hits=512 stale_nonzero_pages=512/512" } |