CVE-2026-46088
Description
In the Linux kernel, the following vulnerability has been resolved:
ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
snd_ctl_elem_init_enum_names() advances pointer p through the names buffer while decrementing buf_len. If buf_len reaches zero but items remain, the next iteration calls strnlen(p, 0).
While strnlen(p, 0) returns 0 and would hit the existing name_len == 0 error path, CONFIG_FORTIFY_SOURCE's fortified strnlen() first checks maxlen against __builtin_dynamic_object_size(). When Clang loses track of p's object size inside the loop, this triggers a BRK exception panic before the return value is examined.
Add a buf_len == 0 guard at the loop entry to prevent calling fortified strnlen() on an exhausted buffer.
Found by kernel fuzz testing through Xiaomi Smartphone.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Missing buf_len validation in snd_ctl_elem_init_enum_names() triggers a panic when fortified strnlen() is called on an exhausted buffer.
Vulnerability
In the Linux kernel, the function snd_ctl_elem_init_enum_names() in sound/core/control.c iterates through a names buffer while decrementing buf_len. If buf_len reaches zero but items remain, the next iteration calls strnlen(p, 0). Under CONFIG_FORTIFY_SOURCE, the fortified strnlen() checks maxlen against __builtin_dynamic_object_size(), which can trigger a BRK exception panic if the compiler loses track of the object size. This affects versions prior to the patched commit e0da8a8cac74 (introduced during the 6.1-rc cycle).
Exploitation
An attacker would need the ability to trigger the vulnerable code path through a crafted SNDRV_CTL_IOCTL_ELEM_ADD or SNDRV_CTL_IOCTL_ELEM_REPLACE ioctl call that provides an enumeration control with a names buffer whose size is exactly exhausted by the parsing loop. This requires local access to the ALSA control interface and the ability to create or modify control elements (typically root or CAP_SYS_ADMIN). The fuzz testing scenario that discovered the bug required repeated manipulation of control element names to force buf_len to zero at the loop entry.
Impact
A successful exploit causes a kernel panic (BRK exception) due to the fortified strnlen() check, leading to a denial of service (system crash). There is no evidence of privilege escalation or data corruption. The panic occurs before the existing name_len == 0 error path can return gracefully.
Mitigation
The fix is included in commit e0da8a8cac74 ("ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()"), which adds a buf_len == 0 guard at the loop entry. This commit has been backported to stable kernel trees as of May 2026 [1]. Users should update to a kernel containing this fix. No workaround is available short of applying the patch or disabling CONFIG_FORTIFY_SOURCE (not recommended).
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
10e0da8a8cac74ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 374e703d15a91c..5e51857635e62a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1648,6 +1648,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
1fbe46d2b727ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index dd4bdb39782cda..3b464260795e9d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1672,6 +1672,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
8ba0214c3dd3ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 0ddade871b524a..6ceb5f977fcddb 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1574,6 +1574,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
654c818a69c2ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 9c3fd5113a6173..c714f2e5596b38 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1574,6 +1574,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
82012fd3e78aALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 934e84e9383806..0b594f89bfb299 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1574,6 +1574,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
1fbe46d2b727ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index dd4bdb39782cda..3b464260795e9d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1672,6 +1672,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
654c818a69c2ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 9c3fd5113a6173..c714f2e5596b38 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1574,6 +1574,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
82012fd3e78aALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 934e84e9383806..0b594f89bfb299 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1574,6 +1574,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
8ba0214c3dd3ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 0ddade871b524a..6ceb5f977fcddb 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1574,6 +1574,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
e0da8a8cac74ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
1 file changed · +4 −1
sound/core/control.c+4 −1 modifieddiff --git a/sound/core/control.c b/sound/core/control.c index 374e703d15a91c..5e51857635e62a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1648,6 +1648,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) /* check that there are enough valid names */ p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { + if (buf_len == 0) { + kvfree(names); + return -EINVAL; + } name_len = strnlen(p, buf_len); if (name_len == 0 || name_len >= 64 || name_len == buf_len) { kvfree(names); -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing buf_len == 0 guard before strnlen() in snd_ctl_elem_init_enum_names() allows fortified strnlen() to trigger a BRK exception panic when the buffer is exhausted."
Attack vector
An attacker can trigger this bug by supplying a crafted ENUMERATED user-space control via the ALSA control interface where the total length of the concatenated enumeration names is exactly exhausted by the number of items declared. When `buf_len` reaches zero but items remain, the loop calls `strnlen(p, 0)`. With `CONFIG_FORTIFY_SOURCE` enabled and Clang as the compiler, the fortified `strnlen()` checks `maxlen` against `__builtin_dynamic_object_size()` before evaluating the return value; if Clang loses track of `p`'s object size, this check triggers a BRK exception panic, causing a kernel crash. The precondition is that the attacker can submit a `SNDRV_CTL_IOCTL_ELEM_ADD` or similar ioctl with crafted enumeration data [patch_id=2659803].
Affected code
The vulnerability resides in the function `snd_ctl_elem_init_enum_names()` in `sound/core/control.c` [patch_id=2659803]. The loop advances pointer `p` through the names buffer while decrementing `buf_len`, but lacks a check for `buf_len == 0` before calling `strnlen(p, buf_len)` on the next iteration.
What the fix does
The patch adds a `buf_len == 0` guard at the top of the loop body in `snd_ctl_elem_init_enum_names()`. If `buf_len` is zero before calling `strnlen()`, the function immediately frees the names buffer and returns `-EINVAL`. This prevents the fortified `strnlen()` from ever being invoked with a zero `maxlen` argument when the compiler cannot track the object size, thereby avoiding the BRK exception panic [patch_id=2659803].
Preconditions
- configCONFIG_FORTIFY_SOURCE must be enabled and the kernel compiled with Clang (which may lose track of the pointer's object size inside the loop)
- inputAttacker must be able to submit an ALSA control ioctl (e.g. SNDRV_CTL_IOCTL_ELEM_ADD) with a crafted ENUMERATED user-space control where the total name buffer length is exactly consumed by the declared number of items
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/1fbe46d2b72754d8bd580e13e59ccb5d3d0e8cb0nvd
- git.kernel.org/stable/c/654c818a69c21d2bea4e8fd9eae7da865df9a5c8nvd
- git.kernel.org/stable/c/82012fd3e78a14360fbc2f1a7491589896704f97nvd
- git.kernel.org/stable/c/8ba0214c3dd32b8ec652947e3f2bc5b8f6e6be9envd
- git.kernel.org/stable/c/e0da8a8cac74f4b9f577979d131f0d2b88a84487nvd
News mentions
0No linked articles in our index yet.