From 89c45623082f0fcb5ec3fc82d4d67a70d4b2f21c Mon Sep 17 00:00:00 2001 From: Shaik Jabida Date: Mon, 1 Jul 2024 14:27:21 +0530 Subject: [PATCH 01/12] dsp: q6lsm: Check size of payload before access check size of payload before access in q6lsm_mmapcallback. The payload size can be either 4 or 8 bytes. Code to verify the payload size is atleast 4 bytes is added. Change-Id: I64b07f44b66fe6793bc80bc99a09fd0521342531 Signed-off-by: Shaik Jabida (cherry picked from commit 14c551f6abb3ad841accc8af91c4a18c0a78b2fe) --- dsp/q6lsm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index 175c8fcb1a7e..aa4127c1ae82 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -2129,8 +2129,18 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) lsm_common.set_custom_topology = 1; return 0; } + + /* + The payload_size can be either 4 or 8 bytes. + It has to be verified whether the payload_size is + atleast 4 bytes. If it is less, returns errorcode. - if (data->payload_size < (2 * sizeof(uint32_t))) { + The opcode for 4 bytes is 0x12A80 + The opcode for 8 bytes is 0x110E8. + + */ + + if (data->payload_size < (2 * sizeof(uint16_t))) { pr_err("%s: payload has invalid size[%d]\n", __func__, data->payload_size); return -EINVAL; From f1a2c1f44d585a50f2bbd3334b15c86dd3594f2e Mon Sep 17 00:00:00 2001 From: Abinath S Date: Fri, 9 Aug 2024 17:53:45 +0530 Subject: [PATCH 02/12] asoc: codec: avoid out of bound write to map array added check for port num and channel iteration are lessthan 8 to avoid out of bound write to 8x8 map array. Change-Id: I4c6fe13a5eb09be623a1c40ce16c5a5e4246e021 Signed-off-by: Abinath S (cherry picked from commit 448a545731195eae632ed5852f8c07133f8a242c) --- asoc/codecs/rouleur/rouleur.c | 5 +++++ asoc/codecs/wcd937x/wcd937x.c | 6 +++++- asoc/codecs/wcd938x/wcd938x.c | 8 +++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/asoc/codecs/rouleur/rouleur.c b/asoc/codecs/rouleur/rouleur.c index b29ba3b43a62..059ef6b015c3 100644 --- a/asoc/codecs/rouleur/rouleur.c +++ b/asoc/codecs/rouleur/rouleur.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -257,6 +258,10 @@ static int rouleur_parse_port_mapping(struct device *dev, for (i = 0; i < map_length; i++) { port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + if (port_num >= MAX_PORT || ch_iter >= MAX_CH_PER_PORT) { + dev_err(dev, "%s: Invalid port or channel number\n", __func__); + goto err_pdata_fail; + } slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index 3306130ccd78..184cb7c533ea 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -315,6 +315,10 @@ static int wcd937x_parse_port_mapping(struct device *dev, for (i = 0; i < map_length; i++) { port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + if (port_num >= MAX_PORT || ch_iter >= MAX_CH_PER_PORT) { + dev_err(dev, "%s: Invalid port or channel number\n", __func__); + goto err_pdata_fail; + } slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 3448e41f0727..8497a36b3002 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -395,6 +395,12 @@ static int wcd938x_parse_port_mapping(struct device *dev, for (i = 0; i < map_length; i++) { port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + + if (port_num >= MAX_PORT || ch_iter >= MAX_CH_PER_PORT) { + dev_err(dev, "%s: Invalid port or channel number\n", __func__); + goto err_pdata_fail; + } + slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; From c3f431c2c71092950f625e5869fa418bbe09463f Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Mon, 10 Feb 2025 17:11:38 +0530 Subject: [PATCH 03/12] dsp: q6adm: Checking array sizeof channel_type there is no check for size of num_channels is less than are equal to channel_type Change-Id: I066857d693665412c52dc579f69acdaac66d5903 Signed-off-by: Manish Kumar --- dsp/q6adm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dsp/q6adm.c b/dsp/q6adm.c index 7455252e2f08..6000c77331e1 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -3910,10 +3910,14 @@ void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate) pr_err("%s: unable to get channal map\n", __func__); goto fail_cmd; } - - for (i = 0; i < mfc_cfg.num_channels; i++) - mfc_cfg.channel_type[i] = + if (mfc_cfg.num_channels <= AUDPROC_MFC_OUT_CHANNELS_MAX) { + for (i = 0; i < mfc_cfg.num_channels; i++) + mfc_cfg.channel_type[i] = (uint16_t) open.dev_channel_mapping[i]; + } else { + pr_err("%s: size of num_channels is greater than channel type \n", __func__); + goto fail_cmd; + } atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); From e5c4f2187cf53a997f624c311b976410de375f96 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Thu, 29 May 2025 00:23:28 +0800 Subject: [PATCH 04/12] audio-kernel: Enable hdmi in audio function for AIO bar HDMI audio using SEC_MI2S_TX. Change-Id: I0b589ffe9fac602bc62adfd228cf9a6227c9b959 Signed-off-by: Yi Zhang --- asoc/msm-pcm-routing-v2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index 7fef53cada56..0834dfa2ccb0 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -26945,6 +26945,10 @@ static const struct snd_kcontrol_new mmul17_mixer_controls[] = { MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, @@ -41375,6 +41379,7 @@ static const struct snd_soc_dapm_route intercon_mi2s[] = { {"MultiMedia29 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia30 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia17 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia18 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia19 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia28 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, From d65a672130769b11823311b2264720a613c5d3f3 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 16:33:36 +0800 Subject: [PATCH 05/12] audio-kernel: Fix wcd938x DMIC unable to record Modify DMIC number to fix wcd938x DMIC can not record issue. Change-Id: I6dfb2156526b1817f6ef9ecfdf1cb670f983afbb Signed-off-by: Zhengchun Li --- asoc/codecs/wcd938x/wcd938x.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 8497a36b3002..744e8739745f 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -3381,35 +3381,35 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, ADC4, 0, adc4_switch, ARRAY_SIZE(adc4_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, DMIC1, + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, DMIC0, 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, DMIC2, + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, DMIC1, 0, dmic2_switch, ARRAY_SIZE(dmic2_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, DMIC3, + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, DMIC2, 0, dmic3_switch, ARRAY_SIZE(dmic3_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, DMIC4, + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, DMIC3, 0, dmic4_switch, ARRAY_SIZE(dmic4_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, DMIC5, + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, DMIC4, 0, dmic5_switch, ARRAY_SIZE(dmic5_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, DMIC6, + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, DMIC5, 0, dmic6_switch, ARRAY_SIZE(dmic6_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, DMIC7, + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, DMIC6, 0, dmic7_switch, ARRAY_SIZE(dmic7_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, DMIC8, + SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, DMIC7, 0, dmic8_switch, ARRAY_SIZE(dmic8_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), From e07673a51a06d2f53930e7a18eb9a54aa9e2edc2 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 16:24:56 +0800 Subject: [PATCH 06/12] asoc: Modification for 8ch capture Patch for 8ch audio record. This modification applies to QCM6490 platform. Change-Id: I2bcdeff53ede9ba3616bb732f54bca7e82792eab Signed-off-by: Zhengchun Li --- asoc/lahaina-port-config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asoc/lahaina-port-config.h b/asoc/lahaina-port-config.h index 62cdd512be20..12f89b0620b5 100644 --- a/asoc/lahaina-port-config.h +++ b/asoc/lahaina-port-config.h @@ -75,8 +75,8 @@ static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = { /* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ static struct port_params tx_frame_params_shima[SWR_MSTR_PORT_LEN] = { {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX1 */ - {7, 5, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ - {7, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ + {7, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ + {7, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX3 */ }; /* 4.8 MHz clock */ From 02200b5f682730669a6c7d48e5a9cab29c283e45 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 18:20:15 +0800 Subject: [PATCH 07/12] asoc: Update dai link for ACM8625S AMP. ACM8625S using i2s dai quin_mi2s_rx. Add ACM8625S AMP dai on dai link. Change-Id: I0653d41b212e954e80fcf70dc4dc2bc7c0739405 Signed-off-by: Zhengchun Li --- asoc/msm_dailink.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/msm_dailink.h b/asoc/msm_dailink.h index c7353b9ae05d..ef588206d321 100644 --- a/asoc/msm_dailink.h +++ b/asoc/msm_dailink.h @@ -957,7 +957,8 @@ SND_SOC_DAILINK_DEFS(quat_mi2s_tx, SND_SOC_DAILINK_DEFS(quin_mi2s_rx, DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.8")), - DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx"), + COMP_CODEC("acm8625s_codec", "acm8625s-hifi")), DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); SND_SOC_DAILINK_DEFS(quin_mi2s_tx, From 62a56196062d4c8cd71b3b9cc05fa6a72b07cc15 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Fri, 4 Jul 2025 17:54:32 +0530 Subject: [PATCH 08/12] asoc: handle heap overflow in effect driver adds a variable prev_config_param_length to track the previous configuration parameter length. This is initialized to 0 and updated after processing the EQ_CONFIG command. This allows the function to compare the current and previous configuration parameter lengths to determine if memory reallocation is necessary. Change-Id: Ib03406b862b6299c421840cc193760096e2db5d9 (cherry picked from commit f770020be262cc1470eea0ce5261e08c74685764) --- asoc/msm-audio-effects-q6-v2.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/asoc/msm-audio-effects-q6-v2.c b/asoc/msm-audio-effects-q6-v2.c index cb795f5bef45..4a7b4b32654e 100644 --- a/asoc/msm-audio-effects-q6-v2.c +++ b/asoc/msm-audio-effects-q6-v2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -1091,7 +1092,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, u32 packed_data_size = 0; u8 *eq_config_data = NULL; u32 *updt_config_data = NULL; - int config_param_length; + int config_param_length, prev_config_param_length = 0; pr_debug("%s\n", __func__); if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) { @@ -1211,7 +1212,12 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, if (!eq_config_data) eq_config_data = kzalloc(config_param_length, GFP_KERNEL); - else + else if (config_param_length != prev_config_param_length) { + if (eq_config_data) + kfree(eq_config_data); + eq_config_data = kzalloc(config_param_length, + GFP_KERNEL); + } else memset(eq_config_data, 0, config_param_length); if (!eq_config_data) { pr_err("%s, EQ_CONFIG:memory alloc failed\n", @@ -1238,6 +1244,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, *updt_config_data++ = eq->per_band_cfg[idx].band_idx; } + prev_config_param_length = config_param_length; break; case EQ_BAND_INDEX: if (length != 1 || index_offset != 0) { @@ -1320,7 +1327,8 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, pr_debug("%s: did not send pp params\n", __func__); invalid_config: kfree(params); - kfree(eq_config_data); + if (eq_config_data) + kfree(eq_config_data); return rc; } EXPORT_SYMBOL(msm_audio_effects_popless_eq_handler); From ad1e75a8ed2b8330151841b8bc322b150a9411c8 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Mon, 16 Jun 2025 19:10:01 +0530 Subject: [PATCH 09/12] asoc: compress: race condition handling in stream cmd put function protect driver data using mutex lock available to protect against race condtion due to multiple thread access. Change-Id: I7dbff3448958b1700ecca2a090fcb915d5809f30 (cherry picked from commit a9530af1782911e76fa765fd9db7c1ad20710f1d) --- asoc/msm-compress-q6-v2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c index 14f549310547..df48c414b05b 100644 --- a/asoc/msm-compress-q6-v2.c +++ b/asoc/msm-compress-q6-v2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.​ */ @@ -4219,6 +4220,7 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, return -EINVAL; } + mutex_lock(&pdata->lock); cstream = pdata->cstream[fe_id]; if (cstream == NULL) { pr_err("%s cstream is null\n", __func__); @@ -4231,7 +4233,6 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(&pdata->lock); if (prtd->audio_client == NULL) { pr_err("%s: audio_client is null\n", __func__); ret = -EINVAL; From bf2e9f51c58f437dcfed7a607dd7e89280d09c57 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Thu, 5 Jun 2025 18:01:42 +0530 Subject: [PATCH 10/12] asoc: lsm: thread safety issue while accessing substream data Added mutex protection while accessing substream data to avoid potential race conditions when accessing this resource from multiple threads. Change-Id: I92e368a73ec2c683c7fcbb4579a19214cc60d1d2 --- asoc/msm-lsm-client.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index bd9b73571263..b18a558848d2 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -42,6 +42,11 @@ #define LSM_IS_LAST_STAGE(client, stage_idx) \ (client->num_stages == (stage_idx + 1)) +struct lsm_char_dev { + /* Protects access to LSM client sessions and shared resources */ + struct mutex lock; +}; + static struct snd_pcm_hardware msm_pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -3106,9 +3111,11 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) { unsigned long flags; struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd; struct msm_pcm_stream_app_type_cfg cfg_data = {0}; + struct lsm_char_dev *lsm_dev; + struct snd_soc_component *component = NULL; int ret = 0; int be_id = 0; int fe_id = 0; @@ -3117,12 +3124,29 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) pr_err("%s: Invalid private_data", __func__); return -EINVAL; } - if (!prtd || !prtd->lsm_client) { - pr_err("%s: No LSM session active\n", __func__); + if (!component || !component->dev) { + pr_err("%s: Invalid component\n", __func__); return -EINVAL; } rtd = substream->private_data; + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } dev_dbg(rtd->dev, "%s\n", __func__); if (prtd->lsm_client->started) { if (prtd->lsm_client->lab_enable) { @@ -3232,6 +3256,7 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) mutex_destroy(&prtd->lsm_api_lock); kfree(prtd); runtime->private_data = NULL; + mutex_unlock(&lsm_dev->lock); return 0; } @@ -3629,6 +3654,14 @@ static struct snd_soc_component_driver msm_soc_component = { static int msm_lsm_probe(struct platform_device *pdev) { + struct lsm_char_dev *lsm_dev; + + lsm_dev = devm_kzalloc(&pdev->dev, sizeof(*lsm_dev), GFP_KERNEL); + if (!lsm_dev) + return -ENOMEM; + + mutex_init(&lsm_dev->lock); + dev_set_drvdata(&pdev->dev, lsm_dev); return snd_soc_register_component(&pdev->dev, &msm_soc_component, NULL, 0); @@ -3636,6 +3669,10 @@ static int msm_lsm_probe(struct platform_device *pdev) static int msm_lsm_remove(struct platform_device *pdev) { + struct lsm_char_dev *lsm_dev; + lsm_dev = dev_get_drvdata(&pdev->dev); + mutex_destroy(&lsm_dev->lock); + snd_soc_unregister_component(&pdev->dev); return 0; From 5fceb1d45f380d709de958a5c45c167708e027b3 Mon Sep 17 00:00:00 2001 From: Akshaya Chirikonda Date: Fri, 13 Jun 2025 12:54:00 +0530 Subject: [PATCH 11/12] asoc: lsm: Race condition protection in confidence levels handling Added mutex protection around freeing confidence_levels to prevent potential race conditions when accessing this memory. Change-Id: I38ec13791a0e99f3ea5f3b2aaf983a1860e7aeeb --- asoc/msm-lsm-client.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index b18a558848d2..85566e51dd76 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include @@ -688,15 +688,47 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, struct lsm_params_info_v2 *p_info) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd = substream->private_data; int rc = 0; + struct lsm_char_dev *lsm_dev; + struct snd_soc_component *component = NULL; + + if (!rtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -EINVAL; + } + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } if (p_info->param_type == LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS) { if (p_info->param_size > MAX_KEYWORDS_SUPPORTED) { dev_err(rtd->dev, "%s: invalid number of snd_model keywords %d, the max is %d\n", __func__, p_info->param_size, MAX_KEYWORDS_SUPPORTED); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -707,6 +739,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: get_conf_levels failed for snd_model %d, err = %d\n", __func__, p_info->model_id, rc); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -727,6 +760,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: invalid confidence levels %d\n", __func__, p_info->param_size); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -738,6 +772,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: get_conf_levels failed, err = %d\n", __func__, rc); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -754,6 +789,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, prtd->lsm_client->confidence_levels = NULL; } } + mutex_unlock(&lsm_dev->lock); return rc; } From 86664f1bbf83f1dc16f77cd8ffab6ce3a3eb35bd Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Fri, 13 Jun 2025 12:59:44 +0530 Subject: [PATCH 12/12] asoc: lsm: thread safety issue in hw params management Added mutex protection while accessing lsm client hw params to avoid potential race conditions when accessing this resource from multiple threads. Change-Id: Ib2cbb954cb145a7a194e8af753cdaf434835b245 --- asoc/msm-lsm-client.c | 67 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index 85566e51dd76..7d69b97ca7c6 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1030,23 +1030,63 @@ static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substrea u32 enable, struct lsm_params_info_v2 *p_info) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct lsm_hw_params *out_hw_params = &prtd->lsm_client->out_hw_params; + struct lsm_hw_params *out_hw_params = NULL; + struct snd_soc_component *component = NULL; + struct lsm_char_dev *lsm_dev = NULL; u8 *chmap = NULL; u32 ch_idx; int rc = 0, stage_idx = p_info->stage_idx; + if (!rtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -EINVAL; + } + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + out_hw_params = &prtd->lsm_client->out_hw_params; + if (!out_hw_params) { + pr_err("%s: Invalid hw params\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + if (prtd->lsm_client->stage_cfg[stage_idx].lab_enable == enable) { dev_dbg(rtd->dev, "%s: Lab for session %d, stage %d already %s\n", __func__, prtd->lsm_client->session, stage_idx, enable ? "enabled" : "disabled"); + mutex_unlock(&lsm_dev->lock); return rc; } chmap = kzalloc(out_hw_params->num_chs, GFP_KERNEL); - if (!chmap) + if (!chmap) { + mutex_unlock(&lsm_dev->lock); return -ENOMEM; + } rc = q6lsm_lab_control(prtd->lsm_client, enable, p_info); if (rc) { @@ -1087,6 +1127,7 @@ static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substrea fail: kfree(chmap); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -3301,21 +3342,36 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct lsm_hw_params *out_hw_params = NULL; struct lsm_hw_params *in_hw_params = NULL; struct snd_soc_pcm_runtime *rtd; + struct lsm_char_dev *lsm_dev = NULL; + struct snd_soc_component *component = NULL; if (!substream->private_data) { pr_err("%s: Invalid private_data", __func__); return -EINVAL; } rtd = substream->private_data; + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: Invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&lsm_dev->lock); + prtd = runtime->private_data; if (!prtd || !params) { dev_err(rtd->dev, "%s: invalid params prtd %pK params %pK", __func__, prtd, params); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } in_hw_params = &prtd->lsm_client->in_hw_params; @@ -3330,6 +3386,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, "%s: Invalid Params sample rate %d period count %d\n", __func__, out_hw_params->sample_rate, out_hw_params->period_count); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -3340,6 +3397,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, } else { dev_err(rtd->dev, "%s: Invalid Format 0x%x\n", __func__, params_format(params)); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -3360,6 +3418,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, */ memcpy(in_hw_params, out_hw_params, sizeof(struct lsm_hw_params)); + mutex_unlock(&lsm_dev->lock); return 0; }