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

netaddr_match union type confusion for RC_NAM cache entries: rc_nam pointer compared as an IPv4 address in the dup-reply-cache hash walk β€” spoofed-source false cache hits and a silently inert duplicate cache for non-AF_INET transports

Summary

Both hash-walk matches call netaddr_match(AF_INET, &rp->rc_haddr, nd->nd_nam) unconditionally (:194,:307), regardless of whether the entry stored an IPv4 address (RC_INETADDR) or a dup'd sockaddr pointer (RC_NAM - the default branch for any non-AF_INET client address, e.g. an AF_INET6 nfsd datagram socket, which nfssvc_addsock accepts without a family check). netaddr_match reads haddr->had_inetaddr for family AF_INET, i.e. the low 32 bits of the rc_nam heap pointer, and compares it to the requester's sin_addr. Consequences: (a) an IPv4 client that spoofs a source address equal to the low 32 bits of a live rc_nam allocation (guessable 32-bit equality oracle observable via hit-vs-miss reply behavior) gets a false cache hit on another (v6) client's entry - dropping its request or resending that client's cached reply (file handles, attributes) to the spoofer; (b) for a v6 transport the match can never succeed, so the duplicate-reply cache is silently inert - every retransmission of a non-idempotent operation re-executes, the exact hazard the cache exists to prevent. Requires admin to run legacy kernel nfsd on a non-AF_INET socket (unusual config, root-only setup). No memory corruption. Not PoC'd (config-gated Low, skipped per contract). Fix: pass the entry's actual family / branch on RC_NAM. [VERIFIED pass2: needs nfsd on v6 socket plus spoofed probes; AF_INET type confusion line-certain; fix compile-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3214 Β· 9 files
FileTypeDescriptionSize
fix.diff β€” 1.0 KB view raw
README.md β€” 400 B ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
build.sh β€” 106 B view raw
run.sh β€” 131 B view raw
manifest.json β€” 512 B view raw
verdict.json β€” 1.4 KB view raw
fix.diff β€” 1.0 KB view raw
env.txt β€” 272 B view raw

DF-3214 -- verification pack

Finding: netaddr_match AF_INET type confusion for RC_NAM cache entries

Status: not_reproduced / impact leak / confidence likely

What was run

n/a

How to reproduce

n/a (needs nfsd on a v6 socket + spoofed v4 probes)

Expected

n/a

See VERDICT.md for the full narrative and verdict.json for the persisted machine verdict. Artifacts: fix.diff.

VERDICT.md
↓ download raw

DF-3214 verification

Kernel: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Bottom line

Type confusion certain by inspection: both hash-walk matches call netaddr_match(AF_INET, &rp->rc_haddr, nd->nd_nam) unconditionally regardless of whether the entry stored an IPv4 address (RC_INETADDR) or a duped sockaddr (RC_NAM, the default for non-AF_INET transports), so a v6-created entry has its rc_nam heap pointer read as an IPv4 address - 32-bit equality oracle for a spoofer and a silently inert duplicate cache for v6. Dynamic proof requires running legacy kernel nfsd on an AF_INET6 datagram socket plus source-spoofed probes; the config gate (admin sets up v6 nfsd) kept it out of this batch. Fix branches on RC_INETADDR; compile-validated.

Kernel references

Exploit chain

(none: availability/correctness finding; no privilege chain)

Fix

branch the cache-walk match on RC_INETADDR

See fix.diff in this directory (git-apply-able against the read-only sys/ tree; applied only inside the disposable verification guest).

Reproduction

build: n/a

run: n/a (needs nfsd on a v6 socket + spoofed v4 probes)

expected: n/a

Notes on the PoC (what changed vs the finding sketch)

(none)

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
↓ fix.diffper-fix-DF-3214

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md walk over nfs_srvcache.c:194/:307 with the RC_INETADDR/RC_NAM storage at :258-275

Verified recommended fix

branch the cache-walk match on RC_INETADDR

Verdict

Type confusion certain by inspection: both hash-walk matches call netaddr_match(AF_INET, &rp->rc_haddr, nd->nd_nam) unconditionally regardless of whether the entry stored an IPv4 address (RC_INETADDR) or a duped sockaddr (RC_NAM, the default for non-AF_INET transports), so a v6-created entry has its rc_nam heap pointer read as an IPv4 address - 32-bit equality oracle for a spoofer and a silently inert duplicate cache for v6. Dynamic proof requires running legacy kernel nfsd on an AF_INET6 datagram socket plus source-spoofed probes; the config gate (admin sets up v6 nfsd) kept it out of this batch. Fix branches on RC_INETADDR; compile-validated.