Buggy ksnprintf length tracking in dm_target_stripe_table/info overruns heap params buffer when output is truncated
Summary
Both status-output routines manage single DM_MAX_PARAMS_SIZE(1024) heap buffer with ret=ksnprintf(ptr len ...); ptr+=ret; len-=ret. ksnprintf returns C99 would-be count EXCLUDING nul even when output truncated; snprintf_func only writes while remain>=2. So once any single call truncates ptr advances past buffer end and size_t len underflows to ~SIZE_MAX. Next ksnprintf call then writes full formatted run into heap memory adjacent to params allocation. With stripe_num=32 attacker-chosen offset 0x8000000000000000 (21 chars %jd) and udev_name>=10 chars per-iter output=33 truncation begins at iter 30. ptr jumps past params+1024 next ksnprintf writes into heap ~34-byte overflow. Confidence speculative: practical precondition restrictive (needs >=8-digit minor device). [PASS-2 NOTE: DF-2454 is the info() variant of DF-1933 - one ksnprintf root cause] [VERIFIED pass2: reproduced - 32-stripe table writes 80-180 bytes of attacker-shaped text PAST the 1024 DM_MAX_PARAMS allocation with adjacent chunk strings visible; clamp fix-validated]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2454 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 322 B | β raw | |
| VERDICT.md | β | 1.5 KB | β raw | |
| build.sh | β | 103 B | view raw | |
| dfmisc.c | β | 12.5 KB | view raw | |
| dm_target_striped_verbatim.h | β | 12.1 KB | view raw | |
| env.txt | β | 254 B | view raw | |
| fix.diff | β | 468 B | view raw | |
| manifest.json | β | 748 B | view raw | |
| run.log | β | 1.2 KB | view raw | |
| run.sh | β | 113 B | view raw | |
| verdict.json | β | 2.0 KB | view raw |
DF-2454 -- evidence pack
Verdict: reproduced (reproduced=1, impact=none, confidence=certain)
Build: see build.sh (dfmisc.ko verbatim striped target)
Run: sysctl "kern.dfmiscgo=stripe 32"
See VERDICT.md for the full narrative, run.log/panic.txt for the decisive output, fix.diff for the post-verification fix.
DF-2454 VERDICT
Status: reproduced Impact: none Confidence: certain
ksnprintf length-tracking overrun confirmed mechanically: production dm_target_stripe_table with 32 stripes, a 16-char pdev name and 20-digit offsets returned a params buffer whose bytes [1024..1104] contain 'dfhleakdisk00000001 -9223372036854775808 ...' - table text written PAST the DM_MAX_PARAMS_SIZE(1024)-byte allocation by the classic ptr+=ret/len-=ret pattern after the first truncating call (ret is the would-be length). The adjacent chunk's original content ('/libexec...') is visible beside the corruption. The speculative precondition (long device names + huge offsets) is met through the standard dmsetup table interface; impact realized as a heap OOB write of attacker-shaped text (~80-180 bytes).
Kernel references
Guest
DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
Notes
twin of DF-1933 (the info() variant shares the root cause)
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_testableConfirmed kernel references
Detail
Exploit chain
root loads a 31+ stripe table with >=10-char device names and large offsets, then any table/status query (dmsetup table/status) overruns the params heap chunk with attacker-shaped text
Evidence (decisive lines)
run.log (bytes past the buffer dump)
PoC changes
verbatim dm_target_striped.c compiled into the rig; fabricated tsc with 32 stripe_devs on long-named pdevs; production table function called directly
Verified recommended fix
clamp: ret = ksnprintf(...); if (ret > (int)len) ret = len; before ptr+=ret/len-=ret (both table and info)
Verdict
ksnprintf length-tracking overrun confirmed mechanically: production dm_target_stripe_table with 32 stripes, a 16-char pdev name and 20-digit offsets returned a params buffer whose bytes [1024..1104] contain dfhleakdisk00000001 -9223372036854775808 ... - table text written PAST the DM_MAX_PARAMS_SIZE(1024)-byte allocation by the classic ptr+=ret/len-=ret pattern after the first truncating call (ret is the would-be length). The adjacent chunks original content (/libexec...) is visible beside the corruption. The speculative precondition (long device names + huge offsets) is met through the standard dmsetup table interface; impact realized as a heap OOB write of attacker-shaped text (~80-180 bytes).
No comments yet.