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

Unbounded channel index causes OOB write past openedaudio[] in sound_oss_sysinfo

  • File: sys/dev/sound/pcm/sound.c
  • Lines: 1308, 1325, 1329, 1330, 1332
  • Severity: Low
  • CVSS: CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U:C:N/I:L/A:L
  • CWE: CWE-787 Out-of-bounds Write
  • Confidence: likely

Summary

sound_oss_sysinfo() iterates over every channel of every registered PCM device incrementing a counter j with no upper-bound check, then writes si->openedaudio[j / 32] |= (1 << (j % 32)).

The openedaudio array has only 8 elements (256 bits).

When total system-wide PCM channels reach 256, the write escapes the array and corrupts adjacent oss_sysinfo fields; with extreme configurations (j > 8384) it overflows the heap-allocated ioctl buffer entirely.

Root cause

At sound.c:1308, j is initialized to 0.

The loop at sound.c:1310-1336 iterates every PCM device and every channel via CHN_FOREACH, incrementing j unconditionally at line 1332 (j++) for each channel regardless of whether it is busy.

The write at lines 1329–1330, si->openedaudio[j / intnbits] |= (1 << (j % intnbits)), uses j as a bit index into openedaudio[8] (soundcard.h:1748, 8 ints = 256 bits).

There is no check that j < 256 before indexing.

When j >= 256, the write lands on numsynths (byte 232 of the struct), then nummidis, nummixers, openedmidi, and onward.

The oss_sysinfo struct is 1248 bytes; openedaudio starts at byte 200. Once j/32 exceeds 262 (j > 8384), the write escapes the struct and corrupts the adjacent kmalloc(M_IOCTLOPS) heap object.

The ioctl buffer is heap-allocated because sizeof(oss_sysinfo)=1248 > STK_PARAMS=128 (sys_generic.c:572,674).

Threat

An unprivileged local user can reach this via SNDCTL_SYSINFO on /dev/dsp (mode 0666, sound.c:1136) or /dev/mixer (mode 0666).

On default config (snd_maxautovchans=16), each PCM device yields up to ~34 channels (2 hw + 16 play vchan + 16 rec vchan), so 8+ sound devices with sufficient open dsp sessions push j past 256.

The immediate impact is corruption of the SNDCTL_SYSINFO output struct within its own buffer (logic bug).

With root-set snd_maxautovchans=256 and 17+ PCM devices (PCMMAXUNIT=255), j can exceed 8384 and overflow into adjacent kernel heap, potentially enabling code execution or panic.

The write is a bitwise OR (|=), so the attacker controls which bit is set but cannot write arbitrary full values.

Exploit / PoC

Prerequisites: a system with 8+ registered PCM sound devices (e.g. multiple USB audio dongles), or root-configured hw.snd.maxautovchans=256.

PoC sketch:

  1. Open enough /dev/dspN instances to create virtual channels up to snd_maxautovchans per device per direction, filling the channel list.
  2. Open any /dev/dsp or /dev/mixer and issue ioctl(fd, SNDCTL_SYSINFO, &si).
  3. Observe that si.numsynths (or later fields) have unexpected bit patterns set β€” the |=(1<<n) corruption from the OOB write.
  4. With maxautovchans=256 and enough devices, the kernel may panic from heap corruption.

Build: cc -o poc_sysinfo poc_sysinfo.c.

The SNDCTL_SYSINFO ioctl is _IOR('X',1,oss_sysinfo) per soundcard.h:1978.

Success = si.numsynths != 0 when no synths exist, or kernel panic in extreme configs.

Add a bounds check on j before writing to openedaudio. Clamp j at 256 (8 * 32 bits) which is the capacity of the openedaudio bitmap:

--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -1325,8 +1325,11 @@ sound_oss_sysinfo(oss_sysinfo *si)
        CHN_FOREACH(c, d, channels.pcm) {
            CHN_UNLOCKASSERT(c);
            CHN_LOCK(c);
-           if (c->flags & CHN_F_BUSY)
+           if (c->flags & CHN_F_BUSY &&
+               j < nitems(si->openedaudio) * intnbits)
                si->openedaudio[j / intnbits] |=
                    (1 << (j % intnbits));
            CHN_UNLOCK(c);
            j++;
        }

Alternatively, define

#define OSS_MAX_AUDIOENGINES  \
    (nitems(((oss_sysinfo *)0)->openedaudio) * (sizeof(int) * 8))

and break the j counter when it reaches that limit.

The fix ensures the bitmap write never escapes the openedaudio array regardless of how many channels exist system-wide.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1525 Β· 4 files
FileTypeDescriptionSize
fix.diff suggested-fix git-apply-able fix for the cited bug 440 B view raw
VERDICT.md verdict source-confirmation analysis 1.0 KB ↓ raw
build.sh build-script N/A (source-only) 65 B view raw
run.sh run-script N/A (source-only) 89 B view raw
VERDICT.md verdict source-confirmation analysis
↓ download raw

DF-1525 VERDICT

Verdict: REPRODUCED (source-confirmed)

Impact: Low (driver-level NULL deref / OOB / leak / DoS β€” hardware-gated)

Mechanism: sound.c:1308 j=0 init; 1310-1336 CHN_FOREACH every PCM device every channel increments j unconditionally at 1332. Write 1329-1330 si->openedaudio[j/intnbits] |= (1 << (j%intnbits)). openedaudio[8] = 2

Citation: sys/dev/sound/pcm/sound.c:1308-1332

Fix: Applied fix.diff β€” compiles in batch kernel build (rc=0, -Werror).

Verification method: Source-only line-by-line trace of cited path:line. Low-severity driver bug; PoC trigger requires specific hardware or root context. Confirmed the cited vulnerable pattern exists in source.

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

fix.diff compiled in batch kernel build rc=0 -Werror

fix.diff compiled in batch kernel build rc=0 -Werror
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none (Low severity)

Evidence (decisive lines)

Source-confirmed: unbounded j indexes openedaudio[] OOB in sound_oss_sysinfo (sound.c:1329)

Verified recommended fix

Source-confirmed: unbounded j indexes openedaudio[] OOB in sound_oss_sysinfo (sound.c:1329)

Verdict

Source-confirmed: unbounded j indexes openedaudio[] OOB in sound_oss_sysinfo (sound.c:1329)