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

feed_matrix_feed FXROUND misrounds: entry rounding sizes the matrixing pass past the destination window and the ialign>oalign path computes a source window that starts before the buffer

Summary

Same generated-table defect consumed at entry count, the j=FXROUND(count-oalign,ialign) window math (src can start before dst), and the partial-return FXDIV. HARNESS-VERIFIED: 4891/23706 checks fail (e.g. 2ch->6ch upmix count=8195 writes at offset 8196 past the window); fixed generator: 0. Unpriv via CHANNELS on any channel-count mismatch. Supersedes this file's earlier 'clean' soak (bad residues not driven).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4847 Β· 16 files
FileTypeDescriptionSize
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
verdict.json β€” 3.5 KB view raw
fxshim.h β€” 6.9 KB view raw
fxsrc.c β€” 2.0 KB view raw
ffmat.c β€” 5.3 KB view raw
fxfmt.c β€” 6.6 KB view raw
ffmat.c β€” 5.3 KB view raw
ffvol.c β€” 5.5 KB view raw
ffmix.c β€” 9.2 KB view raw
dspchurn.c β€” 2.1 KB view raw
ctlchurn.c β€” 991 B view raw
build.sh β€” 119 B view raw
run.sh β€” 140 B view raw
fix.diff β€” 1.0 KB view raw
snd_fxdiv_gen_fixed.awk β€” 4.0 KB ↓ download

DF-4847 β€” feeder_matrix.c FXROUND align-overshoot (evidence pack)

What this proves

The REAL, UNMODIFIED sys/dev/sound/pcm/feeder_matrix.c sizes its feed window with the inexact generated SND_FXROUND/SND_FXDIV macros (see DF-4846 for the table defect β€” misround-up within the claimed [1,65536] domain from xβ‰ˆ5.4K for align 14, xβ‰ˆ8.2K for align 12, 15–40% of counts):

  • :479 count = SND_FXROUND(count, info->oalign) misrounds past the caller's count β†’ pass sized past the destination window.
  • :501 (ialign>oalign, e.g. 7chβ†’5ch) j = SND_FXROUND(count - oalign, ialign) misrounds β‡’ j can exceed countβˆ’oalign by up to ialignβˆ’1 β‡’ src = dst + count - j before the window start AND the source ask window exceeds the destination.
  • :509 SND_FXDIV(FEEDER_FEED(...), ialign) miscounts frames on partial (user-paced) source returns.

The pass-2 soak that previously cleared this file (220k iterations) did not drive the bad-residue count values; this harness enumerates them exactly.

Build / run (guest)

cd /root/fx && sh build.sh && ./ffmat    # baseline: FAIL (4891/23706)
# fixed generator:
cp snd_fxdiv_gen_fixed.h snd_fxdiv_gen.h && cc -O1 -g -o ffmat_fixed ffmat.c fxsrc.c
./ffmat_fixed                            # ALL PASS

Expected output

mat.log: ffmat: checks=23706 failures=4891 -> FAIL, decisive lines: FAIL[T2 upmix ialign=4<oalign=12] in_ch=2 out_ch=6 count=8195 ret=8184 REAR guard (write past window) maxwrite_off=8196 maxask=2728.

In-kernel reachability

feeder_matrix inserted on any channel-count mismatch (feeder_chain.c:284-336, use_matrix when feeder_matrix_compare(origin,target) != 0) β€” an unprivileged SNDCTL_DSP_CHANNELS choice; counts from buffer.c:705-709 as in DF-4846. In-kernel churn logs in the DF-4849 pack.

Fix

fix.diff (shared generator fix). A/B: baseline 4891 failures β†’ fixed 0.

VERDICT.md
↓ download raw

DF-4847 β€” VERDICT

status: reproduced (feeder level, real unmodified code on the audit guest) primitive: up to ialignβˆ’1 byte OOB write past the destination window (including window-preceding underwrite via the :501 misround) + return over-report into sndbuf_acquire (ring overflow) confidence: certain

Root cause

Shared table defect (snd_fxdiv_gen.awk calcdiv single-point validation β€” see DF-4846 VERDICT for the exhaustive enumeration) consumed on the caller's window by feed_matrix_feed:

  • feeder_matrix.c:479 count = SND_FXROUND(count, info->oalign) β€” misround β‡’ count' > count: the source fill and matrixing pass are sized past the window.
  • :494-506 for ialign>oalign: j = SND_FXROUND(count - info->oalign, info->ialign) β€” misround β‡’ j up to count+ialignβˆ’oalignβˆ’1 > count β‡’ src = dst + count - j < dst β€” the source writes BEFORE the destination window and past its end.
  • :509 SND_FXDIV(FEEDER_FEED(...), ialign) β€” frame miscount on partial user-paced returns; apply() then processes frames the source never delivered.

Reproduction (guest, pristine file)

ffmat (mat.log): checks=23706 failures=4891, decisive:

FAIL[T2 upmix ialign=4<oalign=12] in_ch=2 out_ch=6 count=8195 ret=8184 REAR guard (write past window) maxwrite_off=8196 maxask=2728

count=8195 is the first bad value for align 12 (FXROUND(8195,12)=8196): a 2ch→6ch upmix writes past the 8195-byte window (maxwrite_off 8196).

Note: the previous pass-2 result for this file ("clean, 220k iterations") did not include the bad-residue count enumeration; the defect is deterministic arithmetic, not timing.

Kernel reachability

feeder_build_matrix (feeder_chain.c:284-336) on any channel-count mismatch β€” unprivileged SNDCTL_DSP_CHANNELS (2↔6/7 etc.); default chain. Counts as in DF-4846 (buffer.c:705-709). In-kernel churn: no differential anomaly vs aligned control on this no-INVARIANTS kernel (DF-4849 pack logs) β€” same reasoning as DF-4710/DF-4846.

Fix validation

fix.diff (generator, shared): baseline 4891 failures β†’ fixed 0 (ALL PASS) (mat.log vs mat_fixed.log). Fixed table exhaustively exact for all 44 divisors over [1,65536]. fix_status: fixed.

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

fixed
baseline reproduced→ patch + rebuild →patched clean

A/B at harness level, only the generated header swapped: 4891 failures vs 0 (mat.log vs mat_fixed.log). Kernel rebuild A/B not performed (null in-kernel baseline observable on this rig, same standard as DF-4710).

mat_fixed.log (failures=0); fix.diff; snd_fxdiv_gen_fixed.awk
↓ fix.diffper-fix-DF-4847

Confirmed kernel references

Detail

Evidence (decisive lines)

mat.log (baseline: checks=23706 failures=4891, REAR-guard hits with exact counts); mat_fixed.log (fixed table: failures=0 ALL PASS); ffmat.c/fxshim.h/fxsrc.c (harness compiling the pristine feeder_matrix.c with real headers and the real generated table); VERDICT.md

PoC changes

Fresh harness (DF-4846 infrastructure); source pattern lowered to tiny amplitudes so the file's own FEEDMATRIX_CLIP_CHECK errx diagnostic never terminates the run.

Verified recommended fix

Fix snd_fxdiv_gen.awk (domain-exact reciprocals + 64-bit multiply, fix.diff); optionally clamp count in feed_matrix_feed to the caller's window.

Verdict

Reproduced at feeder level on the audit guest against the real, unmodified sys/dev/sound/pcm/feeder_matrix.c: feed_matrix_feed() sizes its pass with the inexact generated SND_FXROUND/SND_FXDIV macros (shared table defect with DF-4846: misround-up within [1,65536] from x~4.7K-8.2K for non-pow2 aligns). :479 FXROUND(count,oalign) can exceed the caller's count (pass sized past the window); :501 FXROUND(count-oalign,ialign) can make j>count so src=dst+count-j lands BEFORE the window and the source window exceeds the destination; :509 FXDIV of a partial user-paced return miscounts frames. Harness: 4891/23706 checks fail with canary-guard hits (e.g. 2ch->6ch upmix, count=8195, FXROUND(8195,12)=8196, write past window); with the fixed generator header 0 failures. The previous pass-2 soak (220k iterations) did not drive the bad-residue counts - the defect is deterministic arithmetic. Reachability: feeder_build_matrix on any channel-count mismatch (feeder_chain.c:284-336), unprivileged SNDCTL_DSP_CHANNELS, default chain; counts user-paced via buffer.c:705-709. In-kernel churn: no differential anomaly vs aligned control on this no-INVARIANTS kernel (logs in DF-4849 pack), as expected for <=ialign-1-byte writes plus silent ring overflow. Impact ceiling: kernel heap OOB write past tmpbuf at exact-page allocation geometry + sndbuf ring invariant breakage, unprivileged, default config.