From 535b305783e9ab808b043b085b7ca95ffd5ea1ee Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Fri, 2 Oct 2026 12:39:45 +0200 Subject: [PATCH] audio: copier: avoid shift by 32 in ALH nibble channel map bitmask_to_nibble_channel_map() fills the nibbles of absent channels with 0xf using 0xFFFFFFFF << (channel_count * 4). channel_mask comes from the host-supplied ALH multi-gateway blob and popcount() == 8 is accepted by copier_set_alh_multi_gtw_channel_map(), so a mask of 0xff makes the shift count 32, which is undefined behaviour for a 32-bit type (UBSan: "shift exponent 32 is too large for 32-bit type"). Xtensa and x86 mask the shift count to 5 bits, so the shift by 32 behaves as a shift by 0 and the map becomes 0xFFFFFFFF: every channel of an 8-channel ALH aggregation is then marked absent in copier_dai_params() instead of getting the identity map 0x76543210. Only fill absent nibbles when there are fewer than 8 channels and use an unsigned literal. Results for all masks with fewer than 8 channels are unchanged. Found by the IPC4 libFuzzer campaign with -fsanitize=undefined. Signed-off-by: Tomasz Leman --- src/audio/copier/copier_dai.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 0e54c0c7a9e5..3861e010e902 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -27,8 +27,13 @@ static uint32_t bitmask_to_nibble_channel_map(uint8_t bitmask) channel_count++; } - /* absent channel is represented as 0xf nibble */ - nibble_map |= 0xFFFFFFFF << (channel_count * 4); + /* Absent channel is represented as 0xf nibble. With all 8 channels present the shift count + * would be 32, which is undefined behavior for 32-bit types. + * On Xtensa and x86 architectures this would result in returning 0xffffffff, marking all + * channels absent. + */ + if (channel_count < 8) + nibble_map |= 0xFFFFFFFF << (channel_count * 4); return nibble_map; }