From 85acdfdb8987fb61bb4962c9a5a9472f8dc740fc Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Thu, 1 Oct 2026 00:27:56 +0530 Subject: [PATCH 1/5] conf: reject absolute include paths containing /../ input_stdio_open() previously opened any absolute path without checking for path traversal. Reject paths that contain "/../" so a planted config cannot read arbitrary files (CWE-22). Signed-off-by: Harsh Raj Singhania --- src/conf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/conf.c b/src/conf.c index a27e6786..1469c7ed 100644 --- a/src/conf.c +++ b/src/conf.c @@ -643,8 +643,11 @@ static int input_stdio_open(snd_input_t **inputp, const char *file, char full_path[PATH_MAX]; int err; - if (file[0] == '/') + if (file[0] == '/') { + if (strstr(file, "/../")) + return -ENOENT; return snd_input_stdio_open(inputp, file, "r"); + } /* search file in user specified include paths. These directories * are subdirectories of /usr/share/alsa. From a1f2154f73d703ae6fa3ae7f6f1de4baa59ea00d Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Thu, 1 Oct 2026 00:28:15 +0530 Subject: [PATCH 2/5] topology: fix uint32_t overflow in control decoder size checks size2 = x->size + x->priv.size was computed in 32-bit arithmetic and could wrap on a 64-bit host, bypassing the subsequent bounds check. Pre-check for overflow then cast to size_t. Affects tplg_decode_control_mixer, tplg_decode_control_enum, and tplg_decode_control_bytes (CWE-190). Signed-off-by: Harsh Raj Singhania --- src/topology/ctl.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 322c461c..93a09f1e 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1315,7 +1315,12 @@ int tplg_decode_control_mixer(snd_tplg_t *tplg, } INIT_LIST_HEAD(&heap); mc = bin; - size2 = mc->size + mc->priv.size; + if (mc->priv.size > size || mc->size > size - mc->priv.size) { + snd_error(TOPOLOGY, "mixer: element sizes overflow (%d, priv %d)", + mc->size, mc->priv.size); + return -EINVAL; + } + size2 = (size_t)mc->size + (size_t)mc->priv.size; if (size2 > size) { snd_error(TOPOLOGY, "mixer: wrong element size (%d, priv %d)", mc->size, mc->priv.size); @@ -1419,7 +1424,12 @@ int tplg_decode_control_enum(snd_tplg_t *tplg, } INIT_LIST_HEAD(&heap); ec = bin; - size2 = ec->size + ec->priv.size; + if (ec->priv.size > size || ec->size > size - ec->priv.size) { + snd_error(TOPOLOGY, "enum: element sizes overflow (%d, priv %d)", + ec->size, ec->priv.size); + return -EINVAL; + } + size2 = (size_t)ec->size + (size_t)ec->priv.size; if (size2 > size) { snd_error(TOPOLOGY, "enum: wrong element size (%d, priv %d)", ec->size, ec->priv.size); @@ -1510,7 +1520,12 @@ int tplg_decode_control_bytes(snd_tplg_t *tplg, return -EINVAL; } bc = bin; - size2 = bc->size + bc->priv.size; + if (bc->priv.size > size || bc->size > size - bc->priv.size) { + snd_error(TOPOLOGY, "bytes: element sizes overflow (%d, priv %d)", + bc->size, bc->priv.size); + return -EINVAL; + } + size2 = (size_t)bc->size + (size_t)bc->priv.size; if (size2 > size) { snd_error(TOPOLOGY, "bytes: wrong element size (%d, priv %d)", bc->size, bc->priv.size); From bc61ba463883b2ffeb365471fb089c70d6de9c58 Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Thu, 1 Oct 2026 00:28:37 +0530 Subject: [PATCH 3/5] pcm: cap route plugin ttable channel dimensions at 1024 csize/ssize grew from config-supplied channel indices with no upper bound before malloc(csize * ssize * sizeof(entry)). Cap both at 1024, consistent with other PCM plugins (CWE-770). Signed-off-by: Harsh Raj Singhania --- src/pcm/pcm_route.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 3836dcc3..34f4e1ee 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -1098,6 +1098,7 @@ static int _snd_pcm_route_determine_ttable(snd_config_t *tt, } if (cchannel + 1 > csize) csize = cchannel + 1; + if (csize > 1024) { SNDERR("route: client channel %d exceeds max (1024)", cchannel); return -EINVAL; } if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) return -EINVAL; snd_config_for_each(j, jnext, in) { @@ -1113,6 +1114,7 @@ static int _snd_pcm_route_determine_ttable(snd_config_t *tt, } if (schannel + 1 > ssize) ssize = schannel + 1; + if (ssize > 1024) { SNDERR("route: slave channel %d exceeds max (1024)", schannel); return -EINVAL; } } } if (csize == 0 || ssize == 0) { From bcd9853da6774b9807d0502236230ff7a412bfe9 Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Thu, 1 Oct 2026 00:28:53 +0530 Subject: [PATCH 4/5] pcm: replace multi plugin binding asserts with -EINVAL checks Sparse binding maps leave sidxs[i] == -1 for gap indices. The previous assert() calls caused SIGABRT in debug builds and OOB reads under NDEBUG. Return -EINVAL with explicit bounds and sign checks instead (CWE-617). Signed-off-by: Harsh Raj Singhania --- src/pcm/pcm_multi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 121c4c20..dc4f9190 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -1121,8 +1121,10 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, } for (i = 0; i < channels_count; ++i) { snd_pcm_multi_channel_t *bind = &multi->channels[i]; - assert(sidxs[i] < (int)slaves_count); - assert(schannels[i] < schannels_count[sidxs[i]]); + if (sidxs[i] < 0 || sidxs[i] >= (int)slaves_count) { + SNDERR("multi: ch %d invalid slave idx %d", i, sidxs[i]); return -EINVAL; } + if (schannels[i] >= schannels_count[sidxs[i]]) { + SNDERR("multi: ch %d channel %d out of range", i, schannels[i]); return -EINVAL; } bind->slave_idx = sidxs[i]; bind->slave_channel = schannels[i]; if (sidxs[i] < 0) From 3b013e64720e224346ffe92aa458c6fb085ed9f4 Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Thu, 1 Oct 2026 00:29:06 +0530 Subject: [PATCH 5/5] ucm: confine sysw and cfg-save paths with realpath() A1 (sysw): execute_sysw() concatenated the sysfs root with a caller path via snprintf() with no traversal check. Use realpath() and reject paths that escape the sysfs root (CWE-22). A2 (cfg-save): execute_cfgsave() opened a caller-supplied filename with no restriction. Confine writes to XDG_RUNTIME_DIR (or /tmp) via realpath() (CWE-73). Signed-off-by: Harsh Raj Singhania --- src/ucm/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ucm/main.c b/src/ucm/main.c index d2b3c2d9..9329dfa3 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -570,6 +570,12 @@ static int execute_sysw(const char *sysw) } snprintf(path, sizeof(path), "%s/%s", e, s); + { char *resolved = realpath(path, NULL); size_t rootlen = strlen(e); + if (!resolved || strncmp(resolved, e, rootlen) != 0) { + free(resolved); free(s); + snd_error(UCM, "sysw path escapes sysfs root: '%s'", path); + return -EINVAL; } free(resolved); } + fd = open(path, O_WRONLY|O_CLOEXEC); if (fd < 0) { free(s); @@ -625,6 +631,11 @@ static int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename) } } + { const char *runtime = getenv("XDG_RUNTIME_DIR"); if (!runtime) runtime = "/tmp"; + char *resolved = realpath(file, NULL); + if (!resolved || strncmp(resolved, runtime, strlen(runtime)) != 0) { + free(resolved); snd_error(UCM, "cfg-save path escapes runtime dir: '%s'", file); + return -EINVAL; } free(resolved); } err = snd_output_stdio_open(&out, file, "w+"); if (err < 0) { snd_error(UCM, "unable to open file '%s': %s", file, snd_strerror(err));