Skip to content

alsa-lib: security hardening — UCM, conf parser, topology, PCM plugins (6 findings) - #527

Open
HarshRajSinghania wants to merge 1 commit into
alsa-project:masterfrom
HarshRajSinghania:alsa-security-hardening-2026-09
Open

HarshRajSinghania wants to merge 1 commit into
alsa-project:masterfrom
HarshRajSinghania:alsa-security-hardening-2026-09

Conversation

@HarshRajSinghania

Copy link
Copy Markdown

This PR addresses six independently-triggered security hardening issues found during a source audit of commit f84cd4c, all verified with proof-of-concept programs.

A3 (shell/system()) and A6 (PCM file popen) are intentional features and are not patched here — hardening suggestions noted inline for maintainer consideration.


A1 — UCM sysw path traversal (CWE-22) · src/ucm/main.c

execute_sysw() concatenates the sysfs root with a caller-supplied string via snprintf() with no .. rejection or realpath() confinement. A UCM path like ../../etc/cron.d/x:value writes to an arbitrary filesystem location. Fix: realpath() confinement — reject if resolved path does not remain within the sysfs root.

A2 — UCM cfg-save unrestricted path (CWE-73) · src/ucm/main.c

execute_cfgsave() calls snd_output_stdio_open(&out, file, "w+") with a raw caller-supplied file and no restriction. Any writable path (e.g. ~/.ssh/authorized_keys) is reachable. Fix: realpath() check — confine to XDG_RUNTIME_DIR (fallback /tmp).

A4 — Config parser absolute include traversal (CWE-22) · src/conf.c

input_stdio_open() immediately opens any absolute path (file[0]=='/') without checking for .. components. A planted config with </../../etc/shadow> can read arbitrary files. Fix: reject paths containing /../.

A5 — Topology control uint32_t integer overflow (CWE-190) · src/topology/ctl.c

size2 = x->size + x->priv.size is computed in 32-bit unsigned arithmetic before being widened to size_t. On a 64-bit host, 0xFFFFFFF0 + 0x20 = 0x10 (wraps), bypassing the subsequent size2 > size guard. Three sites: tplg_decode_control_mixer, tplg_decode_control_enum, tplg_decode_control_bytes (distinct from CVE-2026-25068 which was tplg_decode_control_mixer1). Fix: pre-check for overflow, then (size_t)x->size + (size_t)x->priv.size.

A7 — PCM route plugin unbounded ttable allocation (CWE-770) · src/pcm/pcm_route.c

csize/ssize grow from config-supplied channel indices with no upper bound before malloc(csize * ssize * sizeof(entry)). Index 1073741823malloc(8 GB). Fix: cap both at 1024 (consistent with dmix, softvol, other PCM plugins).

A8 — PCM multi sparse bindings OOB assert (CWE-617) · src/pcm/pcm_multi.c

Sparse binding maps leave sidxs[i] == -1 for gap indices. assert(schannels[i] < schannels_count[sidxs[i]]) then dereferences schannels_count[-1] → SIGABRT (debug) / OOB read (NDEBUG). Fix: replace both assert()s with explicit -EINVAL returns with bounds and sign checks.


Verified: all six PoC programs confirmed on libasound2 1.2.14 / gcc 14.2, commit f84cd4c.

Signed-off-by: Harsh Raj Singhania raj.harshraut@gmail.com

…alformed input

Addresses six independently-triggered issues found during audit of commit f84cd4c:

A1 (UCM sysw, src/ucm/main.c): snprintf() concatenates the sysfs root with
   an attacker-supplied path with no '..' rejection; add realpath() confinement
   to ensure the resolved path stays within the sysfs root. CWE-22.

A2 (UCM cfg-save, src/ucm/main.c): snd_output_stdio_open() called with a
   caller-supplied filename and no path restriction; add realpath() check to
   confine writes to XDG_RUNTIME_DIR (or /tmp). CWE-73.

A4 (conf parser, src/conf.c): absolute-path includes opened without any
   '../' rejection, allowing traversal reads; reject paths containing '/../'.
   CWE-22.

A5 (topology ctl, src/topology/ctl.c): size2 = x->size + x->priv.size is
   computed in uint32_t arithmetic and can wrap on a 64-bit host, bypassing
   the subsequent bounds check. Fix: pre-check for overflow then cast to
   size_t before addition. Affects tplg_decode_control_mixer/enum/bytes
   (three sites). CWE-190.

A7 (PCM route, src/pcm/pcm_route.c): channel indices from config grow csize/
   ssize without bound, leading to an uncapped malloc(csize*ssize*4); cap
   both at 1024 (consistent with other PCM plugins). CWE-770.

A8 (PCM multi, src/pcm/pcm_multi.c): two assert() calls fire on sparse
   channel binding maps (gaps between bindings leave sidxs[i]==-1), causing
   SIGABRT in debug builds and OOB reads under NDEBUG; replace with explicit
   -EINVAL returns. CWE-617.

A3 (UCM shell/system()) and A6 (PCM file popen) are intentional features;
   hardening suggestions (compile-time gate, fork/execve) noted but not patched
   here without maintainer guidance on the desired interface.

All six code-path changes verified standalone against f84cd4c with
proof-of-concept programs.

Signed-off-by: Harsh Raj Singhania <raj.harshraut@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant