drm_gem_create_mmap_offset_size commits the offset-hash + unr publication before drm_vma_offset_add() is known to succeed β failure leaves on_map=true, a leaked idx/hash slot, and a retry that reports success with no vma offset
Summary
DF-specific publication state (unr idx + legacy hash item + on_map=true) is finalized before the Linux-side drm_vma_offset_add result is checked; on failure the publication stays committed (self-healing leak until object release) and any retry early-returns success at :573 while vma_node has no offset. No crash risk (remove-on-never-added is a documented no-op). Unwind-on-failure fix, compile-validated.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4460 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 635 B | β raw | |
| VERDICT.md | β | 2.9 KB | β raw | |
| run.sh | β | 170 B | view raw | |
| build.sh | β | 143 B | view raw | |
| run.log | β | 1.3 KB | view raw | |
| build.log | β | 3.4 KB | view raw | |
| fix.diff | β | 737 B | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 2.9 KB | view raw | |
| env.txt | β | 630 B | view raw |
DF-4460 β drm_gem_create_mmap_offset_size commits hash+unr publication before drm_vma_offset_add is known to succeed; failure leaves on_map=true and a retry returns success with no vma offset
Verify (static)
sh run.sh sys/dev/drm/drm_gem.c
Build (fix compile-validation)
sh build.sh (inside guest, fixed drm_gem.c staged) β drm.ko rebuilds
-Werror clean, RC=0 (build.log).
Files
VERDICT.mdβ ordering analysis, retry hole, impact ceilingrun.sh+run.logβ static proofbuild.sh+build.logβ patched module buildfix.diffβ unwind publication on drm_vma_offset_add failure
DF-4460 β PoC Verification Verdict
File: sys/dev/drm/drm_gem.c (pass 2),
drm_gem_create_mmap_offset_size() at drm_gem.c:566-588.
Guest: DragonFly 6.5-DEVELOPMENT (X86_64_GENERIC), cc 8.3.
Verdict: INCONCLUSIVE at runtime (code defect Certain; hardening/Info)
Root cause
576: obj->map_list.key = alloc_unr(mm->idxunr);
577: ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list);
578: if (ret != 0) { ... free_unr ... return ret; } /* balanced */
583: obj->on_map = true;
585: return drm_vma_offset_add(dev->vma_offset_manager, &obj->vma_node,
586: size / PAGE_SIZE);
The DragonFly-side publication (unr idx + legacy offset hash) is
committed at 576-583 before the Linux-side drm_vma_offset_add()
result is known. When drm_vma_offset_add() fails (drm_mm insert
failure β ENOMEM/sp exhausted range after DRM_FILE_PAGE_OFFSET_SIZE is
carved out, drm_vma_manager.c:200-215), the function returns the error
but leaves:
obj->on_map = trueand the hash item + unr idx committed, and- the early-return retry hole: a subsequent
drm_gem_create_mmap_offset[_size]()seesobj->on_map(573-574) and returns 0 β reporting success whileobj->vma_nodestill has no offset. On the Linux->mmappathdrm_vma_node_offset_addr()would then return 0 and callers hand userspace a bogus 0 offset; on the DragonFlyd_mmap_singlepath the object is still findable via the legacy hash (the DF offset scheme at i915_gem.c:2647-2649 usesmap_list.key, not vma_node), so the user-visible effect is limited to the leaked idx+hash slot held until object release (drm_gem_free_mmap_offset, 529-546, self-heals via the same on_map flag) and the inconsistent state.
Severity: Info (resource lifetime inconsistency, self-healing leak of a 22-bit unr idx + hash bucket per failure; no demonstrated memory safety impact).
Reproduction
Trigger = drm_vma_offset_add() failure = drm_mm range exhaustion /
ENOMEM inside GEM offset creation β not injectable on the QEMU guest
(no drm hardware; no fault-injection knob). Static proof: run.sh /
run.log prints the committed-before-checked ordering in-tree.
Fix validation
fix.diff unwinds the publication (drm_ht_remove_item + free_unr +
on_map=false) when drm_vma_offset_add fails. Compile-validated on the
guest: drm.ko rebuilt with the patch, -Werror, RC=0 (build.log;
combined with sibling DF-4458/DF-4459 hunks). git apply --check
passes against the pristine tree. fix_status=not_testable (trigger not
injectable), compile-validated.
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.
Fix verification
not_testablefix.diff (git apply --check OK) unwinds the publication on drm_vma_offset_add failure so retries start clean. Compile-validated on the guest: drm.ko rebuilt with the fix, -Werror, RC=0 (build.log). Behavioral runs impossible: the trigger (drm_mm insert failure) is not injectable on this guest (fix_status not_testable, compile-validated).
fix.diff; build.log (patched drm.ko full -Werror compile+link, DRM_BUILD_RC=0); VERDICT.md 'Fix validation'
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (ordering: 583 before 585-586, retry early-return 573-574, release-only cleanup at 543); build.log (drm.ko rebuilt with fix, -Werror, DRM_BUILD_RC=0); fix.diff (git apply --check OK)
PoC changes
no seed; static-verification script authored for the pack
Verified recommended fix
Unwind the hash/unr publication (drm_ht_remove_item + free_unr + on_map=false) when drm_vma_offset_add() fails
Verdict
Code defect certain (Info-grade impact): drm_gem_create_mmap_offset_size (drm_gem.c:566-588) allocates the unr idx and inserts the legacy offset-hash item, then sets obj->on_map = true (583) BEFORE learning whether drm_vma_offset_add() (585, drm_vma_manager.c:200-215) succeeded. On failure the function returns the error but leaves the publication committed: the 22-bit idx and hash slot leak until object release (drm_gem_free_mmap_offset 529-546 self-heals via the same on_map flag), obj state is inconsistent, and any retry hits the early-return at 573-574 and reports success while obj->vma_node still has no offset (drm_vma_node_offset_addr would yield 0 for Linux-path callers). On DragonFly the user-visible offset scheme uses map_list.key (i915_gem.c:2647-2649), so the practical impact is the leaked publication + inconsistent state β no demonstrated memory-safety impact. Trigger (drm_mm insert failure / range exhaustion) is not injectable on the QEMU guest; defect proven statically (run.log).
No comments yet.