md_get_mbuf() ignores md_get_mem() failure (silent short copy / INVARIANTS panic) and md_done() leaves md_cur/md_pos dangling
| Field | Value |
|---|---|
| ID | DF-2907 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L |
| CWE | CWE-252 / CWE-459 |
| File | sys/kern/libmchain/subr_mchain.c |
| Lines | 511-521 (esp. :518), 323-330 |
| Area | libmchain (legacy smb consumer) |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | legacy |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
md_get_mbuf (:511-521) ignores the return of md_get_mem(mdp, NULL, size, MB_MZERO) at :518, so if size exceeds the remaining chain the caller still gets success with a short mbuf (on INVARIANTS kernels m_copym panics first via KASSERT). Separately, md_done (:323-330) clears only md_top, leaving md_cur/md_pos pointing at freed mbufs β a dangling-state hazard; in-tree dereference is currently prevented because smb_iod_waitrq only returns error==0 after a fresh record was attached, and every md_done caller re-inits before parsing, but any future caller that parses after a terminal md_done gets a UAF read with an attacker-groomable u_int count underflow in md_get_mem (:478-486). Latent/hardening. Fix: check md_get_mem's return in md_get_mbuf; clear md_cur/md_pos in md_done (already included in DF-2905's fix.diff).
Timeline
- 2026-09-02 Discovered during pass-2 audit of subr_mchain.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2907 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 706 B | β raw | |
| VERDICT.md | β | 1.9 KB | β raw | |
| build.sh | β | 72 B | view raw | |
| dfv_boom.c | β | 3.9 KB | view raw | |
| env.txt | β | 401 B | view raw | |
| fix.diff | β | 1.7 KB | view raw | |
| fix_run.log | β | 264 B | view raw | |
| manifest.json | β | 708 B | view raw | |
| run.log | β | 468 B | view raw | |
| run.sh | β | 120 B | view raw | |
| verdict.json | β | 2.3 KB | view raw |
DF-2907 PoC evidence pack
What
md_get_mbuf ignores md_get_mem failure; md_done leaves md_cur/md_pos dangling.
Build
make (KMOD dfv_boom with KERNBUILDDIR)
Run
kldload smbfs; kldload dfv_boom.ko; sysctl -w dfvboom.m2907=1
Expected
safe form: md_done leaves md_cur/md_pos dangling + stale m_len read; panic form: panic: m_copym: length > size of mbuf chain
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 All logs are full untrimmed captures unless noted. fix.diff is the git-apply-able verified fix (authored after verification; never applied to the audit tree).
DF-2907 - verification verdict
Status: reproduced | reproduced: 1 | impact: panic | confidence: certain
Both halves reproduced on the stock INVARIANTS kernel. (1) Oversize fetch: md_get_mbuf(mdp, 128) against a 64-byte chain panics with panic: m_copym: length > size of mbuf chain - the ignored md_get_mem return at subr_mchain.c:518 lets the call proceed into m_copym with an unsatisfiable length (backtrace: m_copym <- md_get_mbuf <- sysctl trigger); on non-INVARIANTS kernels m_copym breaks with a short copy and the caller gets silent success with a short mbuf - the production form of the claim. (2) md_done leaves md_cur=0xfffff801174d2600 and md_pos dangling over the freed chain (md_top cleared only), and a stale read through md_cur->m_len after md_done returned 64 - the UAF read executed. Fix (check md_get_mem; clear md_cur/md_pos) A/B validated on the fix-all kernel.
Evidence pointers
df2907p_panic.txt: panic m_copym length > size of mbuf chain via md_get_mbuf; run.log: md_done dangling pointers + stale read 64
Kernel references
PoC changes vs the filing sketch
drove the library from a kld harness (needs smbfs.ko loaded for mchain symbols)
Fix
recommendation: check md_get_mem return; clear md_cur/md_pos in md_done
fix status: fixed
see fix_baseline_reproduced fields; A/B on fix-all kernel returned EBADRPC instead of panic
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
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
fixedA/B on fix kernel #2: oversize md_get_mbuf(128) returns 72 (EBADRPC), no panic, guest alive. IMPORTANT: the first fix revision (check md_get_mem AFTER m_copym) did NOT survive A/B - the INVARIANTS KASSERT fires inside m_copym before any post-check; the validated fix pre-computes the remaining chain bytes and rejects before m_copym.
Confirmed kernel references
Detail
Evidence (decisive lines)
df2907p_panic.txt: panic m_copym length > size of mbuf chain via md_get_mbuf; run.log: md_done dangling pointers + stale read 64
PoC changes
drove the library from a kld harness (needs smbfs.ko loaded for mchain symbols)
Verified recommended fix
check md_get_mem return; clear md_cur/md_pos in md_done
Verdict
Both halves reproduced on the stock INVARIANTS kernel. (1) Oversize fetch: md_get_mbuf(mdp, 128) against a 64-byte chain panics with panic: m_copym: length > size of mbuf chain - the ignored md_get_mem return at subr_mchain.c:518 lets the call proceed into m_copym with an unsatisfiable length (backtrace: m_copym <- md_get_mbuf <- sysctl trigger); on non-INVARIANTS kernels m_copym breaks with a short copy and the caller gets silent success with a short mbuf - the production form of the claim. (2) md_done leaves md_cur=0xfffff801174d2600 and md_pos dangling over the freed chain (md_top cleared only), and a stale read through md_cur->m_len after md_done returned 64 - the UAF read executed. Fix (check md_get_mem; clear md_cur/md_pos) A/B validated on the fix-all kernel.
No comments yet.