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

Default drm_gem_dumb_map_offset returns offsets from the wrong address space: vma-manager address without DRM_GEM_MAPPING_KEY bits, unresolvable by (and unrelated to) the hash-key mmap path β€” latent (no in-tree caller)

Summary

Two disjoint offset namespaces grafted onto one file: the default handler reads the vma-manager address while the mmap resolver consumes only the idxunr hash-key form - any driver relying on the default hands users unresolvable offsets (and the split empowers DF-5186). All three KMS drivers override today. Return-the-hash-key-form fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5187 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.2 KB ↓ raw
VERDICT.md β€” 2.0 KB ↓ raw
fix.diff β€” 603 B view raw
manifest.json β€” 659 B view raw
verdict.json β€” 2.2 KB view raw

DF-5187 β€” default drm_gem_dumb_map_offset returns offsets from the wrong address space (latent, dead in-tree)

What

The default drm_gem_dumb_map_offset (reached from drm_mode_mmap_dumb_ioctl's else branch, sys/dev/drm/drm_dumb_buffers.c:128) returns

*offset = drm_vma_node_offset_addr(&obj->vma_node);   /* drm_gem.c:401 */

the raw vma-offset-manager address (drm_mm region starting at DRM_FILE_PAGE_OFFSET_START = 0x100000 pages = 1<<40 bytes β€” drm_gem.c:119-160). But the DragonFly mmap resolver for the DRM cdev only understands the legacy hash-key form:

if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY)   /* 2ULL<<62 */
        return (NULL);                                        /* drm_gem.c:1070 */
offset &= ~DRM_GEM_MAPPING_KEY;
drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset), ...)

and the hash key lives in a different allocator (mm->idxunr, drm_gem.c:153) than the vma node's page index β€” two independent namespaces grafted together in this port. i915's own override returns the correct form (DRM_GEM_MAPPING_OFF(obj->base.map_list.key) | DRM_GEM_MAPPING_KEY, i915_gem.c:2647-2648), which is what everything actually uses.

Consequences for any driver relying on the default:

  1. the MAP_DUMB offset lacks the KEY bits β†’ mmap() on it returns ENODEV (dumb buffers unmap-able β€” functional bug);
  2. nothing in the default path establishes the correspondence the resolver assumes (vma page index vs idxunr key), so the two namespaces can disagree about which object an offset denotes β€” the same mis-wiring that gives DF-5186's race its wrong-object resolution power.

Scope

Latent: all three in-tree KMS drivers override .dumb_map_offset (amdgpu_drv.c:1322, i915_drv.c:3301, radeon_drv.c:693), so no in-tree path uses the default. Info severity; filed so the port's dual-namespace mmap plumbing is on record and because any out-of-tree/currently-unwired GEM driver that trusts the default hands out unmappable (or mis-resolving) offsets.

Fix

Return the hash-key form exactly like i915 (fix.diff). Not verified at runtime (no in-tree consumer; no DRM device on the audit guest) β€” hence status untested.

VERDICT.md
↓ download raw

DF-5187 β€” VERDICT

status: untested Β· Info/latent β€” no PoC attempted (no in-tree consumer of the default path; no DRM device on the audit guest).

Code facts (all verified by reading this tree):

  • drm_mode_mmap_dumb_ioctl falls back to drm_gem_dumb_map_offset when the driver does not override (sys/dev/drm/drm_dumb_buffers.c:120-129).
  • drm_gem_dumb_map_offset returns the vma-manager address (sys/dev/drm/drm_gem.c:401); that address space starts at DRM_FILE_PAGE_OFFSET_START = 0x100000 pages (drm_gem.c:119-123,158-160) and carries no DRM_GEM_MAPPING_KEY bits.
  • The cdev mmap path drm_mmap_single β†’ drm_gem_mmap_single β†’ drm_gem_object_from_offset (drm_drv.c:1256-1270, drm_gem.c:1063-1080) rejects offsets without the KEY bits (ENODEV) and resolves the index through the separate mm->idxunr key space (drm_gem.c:153,576).
  • i915's override returns the resolver-compatible form DRM_GEM_MAPPING_OFF(map_list.key) | DRM_GEM_MAPPING_KEY (i915_gem.c:2647-2648) β€” proof that the two namespaces are distinct and only the hash-key form works.
  • In-tree users of the default: none (.dumb_map_offset set by amdgpu_drv.c:1322, i915_drv.c:3301, radeon_drv.c:693).

Conclusion: real mis-wiring, currently dead in-tree, actionable one-line fix (fix.diff). No runtime verification performed β€” nothing to run against.

kernel_refs

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_testable
baseline no→ patch + rebuild →patched clean

Not applicable - latent dead-in-tree path; nothing to A/B on this guest.

fix.diff
↓ fix.diffper-fix-DF-5187

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (full path trace with line cites); fix.diff (one-line correction matching i915_gem.c:2647-2648)

PoC changes

n/a (Info finding, no PoC attempted per Phase V skip rule for Low/Info)

Verified recommended fix

Return DRM_GEM_MAPPING_OFF(obj->map_list.key) | DRM_GEM_MAPPING_KEY from drm_gem_dumb_map_offset (see fix.diff)

Verdict

Latent mis-wiring, code-verified, not exercised: the DEFAULT drm_gem_dumb_map_offset (drm_dumb_buffers.c:128 -> drm_gem.c:401) returns the raw vma-offset-manager address (no DRM_GEM_MAPPING_KEY bits, drm_gem.c:119-160) while the DragonFly DRM mmap resolver drm_gem_object_from_offset (drm_gem.c:1063-1080) only accepts KEY|OFF(idxunr-hash-key) offsets resolved via the legacy offset_hash - a disjoint allocator. Any driver relying on the default hands out offsets that mmap() rejects with ENODEV, and the two offset namespaces disagree on object identity. All three in-tree KMS drivers override .dumb_map_offset (amdgpu_drv.c:1322, i915_drv.c:3301, radeon_drv.c:693), so no in-tree path uses the default; the audit guest additionally has no DRM device. One-line fix mirrors i915's working form (fix.diff). Info severity.