From ea92da2a3e45ccc350beeb54bafbfb66f85cb224 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 3 Feb 2026 18:25:28 +0100 Subject: [PATCH] Add control API remap fix Resolves: RHEL-144575 Signed-off-by: Jaroslav Kysela --- alsa-git.patch | 344 +++++++++++++++++++++++++++++++++++++++++++++++++ alsa-lib.spec | 7 +- 2 files changed, 349 insertions(+), 2 deletions(-) create mode 100644 alsa-git.patch diff --git a/alsa-git.patch b/alsa-git.patch new file mode 100644 index 0000000..d8254cd --- /dev/null +++ b/alsa-git.patch @@ -0,0 +1,344 @@ +From 7887fbc6f0f660072d1405231703985b72d40cf1 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 26 Jan 2026 15:08:54 +0100 +Subject: [PATCH 1/4] ucm: libconfig parser - fix pathname for substituted file + +The path name substituted file contents and normal file contents +should be handled similary. Use correct function determining +the right base directory name. + +Fixes: 8f5779eb ("ucm: add LibraryConfig support") +Signed-off-by: Jaroslav Kysela +--- + src/ucm/parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index 60861213..baa19144 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -804,7 +804,7 @@ static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) + if (file) { + if (substfile) { + snd_config_t *cfg; +- err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg); ++ err = uc_mgr_config_load_file(uc_mgr, file, &cfg); + if (err < 0) + return err; + err = uc_mgr_substitute_tree(uc_mgr, cfg); +-- +2.52.0 + + +From bc332f4211af98054e7c64aabbe59c7a16ac4e36 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Thu, 29 Jan 2026 15:33:45 +0100 +Subject: [PATCH 2/4] control: ctlparse - make numid parsing more robust + +Also correct the last amixer stderr printf to snd_error(). + +Signed-off-by: Jaroslav Kysela +--- + src/control/ctlparse.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/src/control/ctlparse.c b/src/control/ctlparse.c +index b23234d7..3bd86435 100644 +--- a/src/control/ctlparse.c ++++ b/src/control/ctlparse.c +@@ -156,8 +156,10 @@ char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id) + int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str, + const char **ret_ptr) + { +- int c, size, numid; ++ char buf[64]; ++ int c, size; + int err = -EINVAL; ++ long l; + char *ptr; + + while (isspace(*str)) +@@ -168,12 +170,23 @@ int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str, + while (*str) { + if (!strncasecmp(str, "numid=", 6)) { + str += 6; +- numid = atoi(str); +- if (numid <= 0) { +- fprintf(stderr, "amixer: Invalid numid %d\n", numid); ++ ptr = buf; ++ size = 0; ++ while (*str && *str != ',') { ++ if (size < (int)sizeof(buf)) { ++ *ptr++ = *str; ++ size++; ++ } ++ str++; ++ } ++ *ptr = '\0'; ++ if (safe_strtol(buf, &l) < 0) ++ l = -1; ++ if (l <= 0 || l >= INT32_MAX) { ++ snd_error(CONTROL, "Invalid numid %ld (%s)", l, buf); + goto out; + } +- snd_ctl_elem_id_set_numid(dst, atoi(str)); ++ snd_ctl_elem_id_set_numid(dst, (int)l); + while (isdigit(*str)) + str++; + } else if (!strncasecmp(str, "iface=", 6)) { +@@ -200,7 +213,6 @@ int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str, + goto out; + } + } else if (!strncasecmp(str, "name=", 5)) { +- char buf[64]; + str += 5; + ptr = buf; + size = 0; +-- +2.52.0 + + +From 5f7fe33002d2d98d84f72e381ec2cccc0d5d3d40 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Thu, 29 Jan 2026 16:51:09 +0100 +Subject: [PATCH 3/4] topology: decoder - add boundary check for channel mixer + count + +Malicious binary topology file may cause heap corruption. + +CVE: CVE-2026-25068 + +Signed-off-by: Jaroslav Kysela +--- + src/topology/ctl.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index a0c24518..322c461c 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1250,6 +1250,11 @@ int tplg_decode_control_mixer1(snd_tplg_t *tplg, + if (mc->num_channels > 0) { + map = tplg_calloc(heap, sizeof(*map)); + map->num_channels = mc->num_channels; ++ if (map->num_channels > SND_TPLG_MAX_CHAN || ++ map->num_channels > SND_SOC_TPLG_MAX_CHAN) { ++ snd_error(TOPOLOGY, "mixer: unexpected channel count %d", map->num_channels); ++ return -EINVAL; ++ } + for (i = 0; i < map->num_channels; i++) { + map->channel[i].reg = mc->channel[i].reg; + map->channel[i].shift = mc->channel[i].shift; +-- +2.52.0 + + +From 166407dae4c91583aff43624ce1eafb8695a4482 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Tue, 3 Feb 2026 17:46:02 +0100 +Subject: [PATCH 4/4] control: remap - fix numid lookup issue + +The 'amixer controls' and 'amixer cget numid=' combo was not working +correctly when the remapping was active. This assert was trigerred: + +amixer: control.c:427: snd_ctl_elem_info: Assertion `ctl && info && (info->id.name[0] || info->id.numid)' failed + +All elements must be loaded and mapping created to build +the numid -> fullid link. + +Signed-off-by: Jaroslav Kysela +--- + src/control/control_remap.c | 79 ++++++++++++++++++++++++++++++++----- + 1 file changed, 69 insertions(+), 10 deletions(-) + +diff --git a/src/control/control_remap.c b/src/control/control_remap.c +index 7d90d7ad..f7f118aa 100644 +--- a/src/control/control_remap.c ++++ b/src/control/control_remap.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -97,8 +98,11 @@ typedef struct { + + typedef struct { + snd_ctl_t *child; +- int numid_remap_active; ++ bool list_complete; ++ bool numid_remap_active; + unsigned int numid_app_last; ++ unsigned int list_first; ++ unsigned int list_last; + + size_t numid_items; + size_t numid_alloc; +@@ -125,6 +129,8 @@ typedef struct { + } snd_ctl_remap_t; + #endif + ++static int remap_load_list(snd_ctl_remap_t *priv); ++ + static snd_ctl_numid_t *remap_numid_temp(snd_ctl_remap_t *priv, unsigned int numid) + { + priv->numid_temp.numid_child = numid; +@@ -137,6 +143,8 @@ static snd_ctl_numid_t *remap_find_numid_app(snd_ctl_remap_t *priv, unsigned int + snd_ctl_numid_t *numid; + size_t count; + ++ if (numid_app == 0) ++ return NULL; + if (!priv->numid_remap_active) + return remap_numid_temp(priv, numid_app); + numid = priv->numid; +@@ -151,6 +159,8 @@ static snd_ctl_numid_t *remap_numid_new(snd_ctl_remap_t *priv, unsigned int numi + { + snd_ctl_numid_t *numid; + ++ if (numid_app == 0) ++ return NULL; + if (priv->numid_alloc == priv->numid_items) { + numid = realloc(priv->numid, (priv->numid_alloc + 16) * sizeof(*numid)); + if (numid == NULL) +@@ -187,6 +197,8 @@ static snd_ctl_numid_t *remap_find_numid_child(snd_ctl_remap_t *priv, unsigned i + snd_ctl_numid_t *numid; + size_t count; + ++ if (numid_child == 0) ++ return NULL; + if (!priv->numid_remap_active) + return remap_numid_temp(priv, numid_child); + numid = priv->numid; +@@ -282,8 +294,11 @@ static int remap_id_to_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_c + { + snd_ctl_remap_id_t *rid; + snd_ctl_numid_t *numid; ++ bool reloaded = false; ++ int err; + + debug_id(id, "%s enter\n", __func__); ++_retry: + rid = remap_find_id_app(priv, id); + if (rid) { + if (rid->id_app.numid == 0) { +@@ -295,13 +310,21 @@ static int remap_id_to_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_c + } + *id = rid->id_child; + } else { +- if (remap_find_id_child(priv, id)) +- return -ENOENT; + numid = remap_find_numid_app(priv, id->numid); +- if (numid) ++ if (numid) { + id->numid = numid->numid_child; +- else +- id->numid = 0; ++ } else { ++ if (reloaded) ++ return -ENOENT; ++ if (priv->list_complete) ++ return -ENOENT; ++ /* build whole numid mapping */ ++ err = remap_load_list(priv); ++ if (err < 0) ++ return err; ++ reloaded = true; ++ goto _retry; ++ } + } + *_rid = rid; + debug_id(id, "%s leave\n", __func__); +@@ -329,6 +352,7 @@ static int remap_id_to_app(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_ctl + id->numid = numid->numid_app; + } + } ++ debug_id(id, "%s rid %p\n", __func__, rid); + return err; + } + +@@ -466,9 +490,8 @@ static int snd_ctl_remap_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) + return snd_ctl_card_info(priv->child, info); + } + +-static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list) ++static int _snd_ctl_remap_elem_list(snd_ctl_remap_t *priv, snd_ctl_elem_list_t *list) + { +- snd_ctl_remap_t *priv = ctl->private_data; + snd_ctl_elem_id_t *id; + snd_ctl_remap_id_t *rid; + snd_ctl_numid_t *numid; +@@ -483,13 +506,17 @@ static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list) + id = &list->pids[index]; + rid = remap_find_id_child(priv, id); + if (rid) { +- rid->id_app.numid = id->numid; +- *id = rid->id_app; ++ assert(id->numid > 0); ++ rid->id_child.numid = id->numid; + } + numid = remap_find_numid_child(priv, id->numid); + if (numid == NULL) + return -EIO; + id->numid = numid->numid_app; ++ if (rid) { ++ rid->id_app.numid = id->numid; ++ *id = rid->id_app; ++ } + } + if (list->offset >= list->count + priv->map_items + priv->sync_switch_items) + return 0; +@@ -510,9 +537,40 @@ static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list) + } + } + list->count += priv->map_items + priv->sync_switch_items; ++ if (list->offset < priv->list_first) ++ priv->list_first = list->offset; ++ if (list->offset == priv->list_last && list->offset + list->used > priv->list_last) ++ priv->list_last = list->offset + list->used; ++ priv->list_complete = priv->list_first == 0 && list->count == priv->list_last; + return 0; + } + ++static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list) ++{ ++ snd_ctl_remap_t *priv = ctl->private_data; ++ ++ return _snd_ctl_remap_elem_list(priv, list); ++} ++ ++static int remap_load_list(snd_ctl_remap_t *remap) ++{ ++ snd_ctl_elem_list_t list; ++ int err = 0; ++ ++ memset(&list, 0, sizeof(list)); ++ do { ++ err = _snd_ctl_remap_elem_list(remap, &list); ++ if (err < 0) ++ break; ++ err = snd_ctl_elem_list_alloc_space(&list, list.count); ++ if (err < 0) ++ break; ++ } while (list.count != list.used); ++ if (err < 0) ++ free(list.pids); ++ return err; ++} ++ + #ifndef DOC_HIDDEN + #define ACCESS_BITS(bits) \ + (bits & (SNDRV_CTL_ELEM_ACCESS_READWRITE|\ +@@ -1674,6 +1732,7 @@ int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *rema + + priv->numid_remap_active = priv->map_items > 0 || priv->sync_items; + ++ priv->list_first = UINT_MAX; + priv->child = child; + err = snd_ctl_new(&ctl, SND_CTL_TYPE_REMAP, name, mode); + if (err < 0) { +-- +2.52.0 + diff --git a/alsa-lib.spec b/alsa-lib.spec index 4a6559f..81d3036 100644 --- a/alsa-lib.spec +++ b/alsa-lib.spec @@ -6,13 +6,13 @@ %define version_alsa_ucm 1.2.15.3 %define version_alsa_tplg 1.2.5 -%global lib_patch 0 +%global lib_patch 1 %global ucm_patch 0 Summary: The Advanced Linux Sound Architecture (ALSA) library Name: alsa-lib Version: %{version_alsa_lib} -Release: 1%{?prever_dot}%{?dist} +Release: 2%{?prever_dot}%{?dist} License: LGPL-2.1-or-later URL: http://www.alsa-project.org/ @@ -178,6 +178,9 @@ rm %{buildroot}/%{_includedir}/asoundlib.h %{_datadir}/alsa/topology %changelog +* Tue Feb 10 2026 Jaroslav Kysela - 1.2.15.3-2 +- fix control API remap issue + * Thu Jan 8 2026 Jaroslav Kysela - 1.2.15.3-1 - update to alsa-lib 1.2.15.3 and alsa-ucm-conf 1.2.15.3