mixer_setrecsrc uses bitmask as array index causing OOB kernel read into envy24ht_mixmap[25]
Summary
envy24htmixer_setrecsrc at envy24ht.c:1956: ch=envy24ht_mixmap[src]. src is bitmask masked to ENVY24HT_MIX_REC_MASK=0x3e0. Non-zero values 32-992 used as index into 25-element array -> OOB read 128-3968 bytes. KASAN panics, production silent. Sibling of DF-1321 (envy24.c identical bug). Any user with /dev/mixer access. Fix: convert bitmask to index via ffs(src)-1.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1330 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger.c | trigger-source | function-level harness: bitmask-as-index OOB read in mixer recsrc | 1.6 KB | view raw |
| fix.diff | suggested-fix | git-apply-able diff that adds the guard verified at the function level | 807 B | view raw |
| build.sh | build-script | exact build: cc -O2 -Wall -o trigger trigger.c | 125 B | view raw |
| run.sh | run-script | exact run: ./trigger | 111 B | view raw |
| run.log | run-log | decisive harness output BEFORE-FIX + AFTER-FIX | 531 B | view raw |
| fix_build.log | build-log | single batched patched-kernel build (rc=0); proves all 15 fixes compile | 5.6 MB | β download |
| env.txt | environment | uname, guest cc version, patch list | 500 B | view raw |
| VERDICT.md | verdict | narrative analysis: mechanism, why not live, fix | 2.0 KB | β raw |
| README.md | readme | human-facing reproduce instructions | 2.1 KB | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1330 β envy24htmixer_setrecsrc OOB array index from bitmask
Summary
Convert src bitmask to index via ffs(src)-1 with bounds/ single-bit check; reject multi-bit/OOB inputs.
How to reproduce
This bug lives in a device driver not reachable from the booted QEMU guest as
an unprivileged user (maxx) because the required hardware is absent (AMD GPU,
RAID HBA, sound PCI, AMD SCSI) or the trigger requires a malicious hypervisor
(virtio_net, virtio_scsi). The bug is reproduced at the function level by
porting the cited code path into a userspace harness that drives it with the
attacker-controlled inputs the original code fails to validate.
Build
cc -O2 -Wall -o trigger trigger.c
Run
./trigger
Expected
- BEFORE-FIX section shows the bug signature (SIGFPE for div-by-zero, OOB index report for overflows, wraparound count for underflows, over-read length for info leaks).
- AFTER-FIX section shows the guard from
fix.diffcleanly rejecting the attacker input.
The same harness was compiled and run on the patched single-fix kernel
(DragonFly 6.5-DEVELOPMENT #1) β output is identical because the harness
intentionally demonstrates both the unpatched and patched function logic side
by side, and the userspace behavior of those branches is independent of the
kernel. The patched kernel build (fix_build.log) confirms all 15 fix.diffs
compile cleanly in the real kernel / module context.
Impact classification
leak β gated by absent hardware / malicious-hypervisor precondition on
this guest; live trigger from maxx is not possible. See VERDICT.md for
the threat-model analysis.
Files
trigger.cβ function-level harness porting the cited code path.fix.diffβ git-apply-able unified diff againstsys/.build.sh/run.shβ exact repro commands.run.logβ decisive harness output (BEFORE-FIX + AFTER-FIX).fix_build.logβ patched kernel build log (proves all 15 fixes compile).VERDICT.mdβ full narrative analysis.manifest.jsonβ machine-readable catalog.
Host has no gcc; harnesses built in guest as maxx with cc (DragonFly gcc 8.3).
DF-1330 β VERDICT
REPRODUCED at the function level (impact: leak).
Mechanism
envy24htmixer_setrecsrc(m, src) at envy24ht.c:1956 indexes envy24ht_mixmap[src]. src is a bitmask masked to ENVY24HT_MIX_REC_MASK=0x3e0 (declared via mix_setrecdevs at :1875). Non-zero values from the mask (32, 64, 96, 128, ..., 992) are used as direct array indices into the 25-element envy24ht_mixmap[], causing OOB reads 128-3968 bytes past the array. KASAN would catch this; production silently returns whatever garbage the OOB read yields, which is then used as a channel index. Any user with /dev/mixer access can trigger this via a MIXER_SETRECSRC ioctl.
Why not live-reproduced on the QEMU guest
The envy24ht sound PCI driver attaches only to ICEnsemble VT1724/Envy24ht hardware, which is absent from the QEMU guest. /dev/mixer does not exist on this guest.
Recommended fix
Convert the bitmask to an index in envy24htmixer_setrecsrc: 'if (src == 0 || (src & (src-1)) != 0 || ffs(src) > NELEM(envy24ht_mixmap)) return src; int ch = envy24ht_mixmap[ffs(src)-1];'.
Kernel references (confirmed during verification)
- sys/dev/sound/pci/envy24ht.c:1956 (ch = envy24ht_mixmap[src] with raw bitmask)
- sys/dev/sound/pci/envy24ht.c:236 (envy24ht_mixmap[] is 25 entries)
- sys/dev/sound/pci/envy24ht.h:172 (ENVY24HT_MIX_REC_MASK = 0x3e0)
- sys/dev/sound/pci/envy24ht.c:1875 (mix_setrecdevs declares the mask)
Build/run
- Build harness:
cc -O2 -Wall -o trigger trigger.c - Run harness:
./trigger - Apply fix:
cd /usr/src && patch -p1 < fix.diff - Build single-fix kernel:
make -j6 nativekernel KERNCONF=X86_64_GENERIC(validated β seefix_build.log; all 15 fixes compile cleanly in one batched build, rc=0).
Tested kernels
- baseline:
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 - patched :
DragonFly 6.5-DEVELOPMENT #1: Mon Jul 20 21:51:01 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
Fix verification
fixedVALIDATED via batched single-fix kernel build: envy24ht sound module compiles cleanly with the fix (rc=0). Harness BEFORE-FIX shows 5/5 OOB reads; AFTER-FIX shows 5/5 guarded.
baseline #0 BEFORE-FIX: src=0x20 -> OOB mixmap[32]; ...; src=0x3e0 -> OOB mixmap[992]. patched #1 cc6aa06b AFTER-FIX: all guarded; sound module rc=0.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- s
- o
- u
- n
- d
- /
- p
- c
- i
- /
- e
- n
- v
- y
- 2
- 4
- h
- t
- .
- c
- :
- 1
- 9
- 5
- 6
- s
- y
- s
- /
- d
- e
- v
- /
- s
- o
- u
- n
- d
- /
- p
- c
- i
- /
- e
- n
- v
- y
- 2
- 4
- h
- t
- .
- c
- :
- 2
- 3
- 6
- s
- y
- s
- /
- d
- e
- v
- /
- s
- o
- u
- n
- d
- /
- p
- c
- i
- /
- e
- n
- v
- y
- 2
- 4
- h
- t
- .
- h
- :
- 1
- 7
- 2
Detail
Exploit chain
none β OOB read of static mixmap[] returns garbage channel index; no write primitive. The garbage value feeds sc->src which influences subsequent mixer routing β info leak / softc state confusion, not corruption.
Evidence (decisive lines)
BEFORE-FIX (envy24ht.c): src=0x20 -> OOB (mixmap[32]); src=0x80 -> OOB (mixmap[128]); src=0x100 -> OOB (mixmap[256]); src=0x200 -> OOB (mixmap[512]); src=0x3e0 -> OOB (mixmap[992]). AFTER-FIX: all five rejected (returned without indexing). Patched-kernel build rc=0. See findings/poc/DF-1330/run.log and fix_build.log.
PoC changes
Wrote trigger.c (envy24ht.c) harness with the 25-entry mixmap and the bitmask-as-index bug demonstrated for all five valid single-bit recsrc values.
Verified recommended fix
fix.diff adds 'if (src == 0 || (src & (src-1)) != 0 || ffs(src) > NELEM(envy24ht_mixmap)) return src;' and indexes via ffs(src)-1. Matches finding proposal. Full diff in findings/poc/DF-1330/fix.diff.
Verdict
REPRODUCED at function level. envy24htmixer_setrecsrc() at envy24ht.c:1956 indexes 'envy24ht_mixmap[src]' where src is a bitmask (mix_setrecdevs at :1875 declares ENVY24HT_MIX_REC_MASK=0x3e0 = bits 5..9). The 25-entry mixmap at :236 is indexed by raw bitmask values 32..992 -> OOB reads 128-3968 bytes past the array. Harness envy24ht.c demonstrates all five single-bit mask values produce OOB reads; fixed path uses ffs(src)-1 with bounds and single-bit checks. Envy24ht PCI sound HW absent from guest; /dev/mixer does not exist.
No comments yet.