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

pmap_extract() KVA path duplicates the PDE validity check instead of testing the PTE β€” bogus non-zero physical address returned for unmapped kernel VA

Summary

Kernel branch re-tests '*pt & PG_V' (the PDE, already tested) instead of '*ptep & PG_V': with a present PT page but zero PTE it returns (va & PAGE_MASK) as a physical address instead of 0. No live in-tree KVA caller today (busdma uses pmap_kextract; sglist uses the correct user branch) - landmine for future callers like _sglist_append_buf DMA programming. One-operand fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5245 Β· 2 files
FileTypeDescriptionSize
README.md β€” 2.4 KB ↓ raw
verdict.json β€” 2.0 KB view raw

DF-5245 β€” pmap_extract() KVA path checks the PDE instead of the PTE

What

pmap_extract() (sys/platform/pc64/x86_64/pmap.c:1717-1769), kernel-address branch:

1733  pt = pmap_pt(pmap, va);              /* PD slot (pointer to PT entry) */
1734  if (pt && (*pt & pmap->pmap_bits[PG_V_IDX])) {   /* PDE valid */
1735      if (*pt & PG_PS) { ... 2MB case ok ... }
1737      else {
1738          ptep = pmap_pt_to_pte(*pt, va);          /* PTE slot */
1739          if (*pt & pmap->pmap_bits[PG_V_IDX]) {   /* BUG: re-tests *pt
                                                         (the PDE), should
                                                         test *ptep */
1740              rtval = *ptep & PG_FRAME;
1741              rtval |= va & PAGE_MASK;
1742          }
      }
  }

Line 1739 duplicates the PDE validity test instead of testing the PTE (*ptep). When the page-table page exists (PDE valid) but the PTE is 0 (page not entered / already removed), pmap_extract() returns (va & PAGE_MASK) β€” the page offset β€” as a "valid" physical address instead of 0 (its documented failure value).

Impact

Callers that use the return value without re-validating (e.g. _sglist_append_buf() in sys/kern/subr_sglist.c:126-160, which feeds ss_paddr straight into a scatter/gather list for DMA) can program a bogus low physical address into device I/O. On pc64 the KVA branch of pmap_extract() currently has no in-tree caller that passes a kernel VA (busdma uses pmap_kextract(); sglist user paths use the correctly-checked user branch at pmap.c:1756), so no live impact is demonstrated β€” filed as a Low-severity correctness landmine with certain code-level confidence.

Fix

--- a/sys/platform/pc64/x86_64/pmap.c
+++ b/sys/platform/pc64/x86_64/pmap.c
@@ -1736,7 +1736,7 @@
            } else {
                ptep = pmap_pt_to_pte(*pt, va);
-               if (*pt & pmap->pmap_bits[PG_V_IDX]) {
+               if (*ptep & pmap->pmap_bits[PG_V_IDX]) {
                    rtval = *ptep & PG_FRAME;
                    rtval |= va & PAGE_MASK;
                }

Verification

Not executed on the guest: the buggy branch is not reachable from any in-tree caller with a kernel VA on this platform (verified by grepping all pmap_extract call sites), so there is no runtime trigger to build β€” finding is certain by inspection, severity Low, no runtime impact demonstrated. No fix.diff beyond the one-liner above (also embedded here and in the finding markdown).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not tested - trivial one-line correctness fix; branch has no reachable caller on pc64

README.md contains the one-line diff
per-fix-DF-5245

Confirmed kernel references

Detail

Evidence (decisive lines)

README.md in this pack: quoted code pmap.c:1733-1743 showing the duplicated *pt test; caller survey (sys/kern/subr_sglist.c:126, sys/vfs/procfs/procfs_map.c:128) showing the KVA branch is dead on pc64 today

PoC changes

none - no runtime PoC (Low severity, dead branch on this platform; contract allows skipping verification for Low/Info)

Verified recommended fix

pmap.c:1739: change 'if (pt & pmap->pmap_bits[PG_V_IDX])' to 'if (ptep & pmap->pmap_bits[PG_V_IDX])'.

Verdict

pmap_extract() kernel-VA branch re-tests the PDE (pt) where it must test the PTE (ptep) at pmap.c:1739, so a not-present PTE under a valid page directory yields rtval = (va & PAGE_MASK) instead of the documented failure value 0. Certain by inspection. No runtime trigger exists on pc64: no in-tree caller reaches this branch with a kernel VA (busdma uses pmap_kextract; sglist/procfs use the user branch), so impact is latent (any future caller trusting the return, e.g. for DMA sglists, would receive a plausible-looking bogus physical address). Low severity, not executed on the guest.