From 7289a6a51e070fd0d8b86ff2e0db77c252740361 Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Tue, 12 Feb 2019 17:01:22 +0800 Subject: [PATCH 01/17] dsp: validate token before usage as array index Token from DSP might be invalid for array index. Validate the token before being used as array index. Change-Id: I9f47e1328d75d9f9acf7e85ddb452019b6eced0a Signed-off-by: Xiaojun Sang --- sound/soc/msm/qdsp6v2/q6afe.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index 0524ca21feba..20c933b80c66 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -482,6 +482,15 @@ static int32_t afe_lpass_resources_callback(struct apr_client_data *data) return 0; } +static bool afe_token_is_valid(uint32_t token) +{ + if (token >= AFE_MAX_PORTS) { + pr_err("%s: token %d is invalid.\n", __func__, token); + return false; + } + return true; +} + static int32_t afe_callback(struct apr_client_data *data, void *priv) { if (!data) { @@ -574,7 +583,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) ret = afe_lpass_resources_callback(data); atomic_set(&this_afe.state, 0); - wake_up(&this_afe.wait[data->token]); + if (afe_token_is_valid(data->token)) + wake_up(&this_afe.wait[data->token]); + else + return -EINVAL; if (!ret) { return ret; } @@ -610,7 +622,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) case AFE_SVC_CMD_SET_PARAM_V2: case AFE_CMD_REQUEST_LPASS_RESOURCES: atomic_set(&this_afe.state, 0); - wake_up(&this_afe.wait[data->token]); + if (afe_token_is_valid(data->token)) + wake_up(&this_afe.wait[data->token]); + else + return -EINVAL; break; case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER: break; @@ -622,7 +637,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) break; case AFE_CMD_ADD_TOPOLOGIES: atomic_set(&this_afe.state, 0); - wake_up(&this_afe.wait[data->token]); + if (afe_token_is_valid(data->token)) + wake_up(&this_afe.wait[data->token]); + else + return -EINVAL; pr_debug("%s: AFE_CMD_ADD_TOPOLOGIES cmd 0x%x\n", __func__, payload[1]); break; @@ -678,7 +696,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) else this_afe.mmap_handle = payload[0]; atomic_set(&this_afe.state, 0); - wake_up(&this_afe.wait[data->token]); + if (afe_token_is_valid(data->token)) + wake_up(&this_afe.wait[data->token]); + else + return -EINVAL; } else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) { port_id = (uint16_t)(0x0000FFFF & payload[0]); } From 0fe53af86212bd9fab635c526efff001e0584102 Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Fri, 8 Feb 2019 15:29:11 +0530 Subject: [PATCH 02/17] icnss: Defer modem graceful shutdown until probe complete In case WLAN driver probe is in progress and modem graceful shutdown occurs and if modem shutdown request is sent just before the mode on request sent to firmware, firmware may end up in illegal memory access. To address this issue, modem notifier needs to be blocked needs for probe to complete or max 5 seconds timeout. CRs-Fixed: 2381846 Change-Id: I9e13a11c56059cb29e161c34df11de484f87ac5e Signed-off-by: Sandeep Singh --- drivers/soc/qcom/icnss.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index fae06806b7db..f1eeb66ed80a 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -75,6 +75,8 @@ module_param(qmi_timeout, ulong, 0600); #define ICNSS_MAX_PROBE_CNT 2 +#define PROBE_TIMEOUT 5000 + #define icnss_ipc_log_string(_x...) do { \ if (icnss_ipc_log_context) \ ipc_log_string(icnss_ipc_log_context, _x); \ @@ -299,6 +301,7 @@ enum icnss_driver_state { ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, + ICNSS_DRIVER_LOADING, }; struct ce_irq_list { @@ -491,6 +494,7 @@ static struct icnss_priv { u8 requesting_sub_system; u16 line_number; char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; + struct completion driver_probed; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -2203,6 +2207,8 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) icnss_hw_power_on(priv); + set_bit(ICNSS_DRIVER_LOADING, &priv->state); + reinit_completion(&penv->driver_probed); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = priv->ops->probe(&priv->pdev->dev); probe_cnt++; @@ -2212,9 +2218,13 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) if (ret < 0) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, priv->state, probe_cnt); + complete(&penv->driver_probed); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); goto out; } + complete(&penv->driver_probed); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); set_bit(ICNSS_DRIVER_PROBED, &priv->state); return 0; @@ -2350,6 +2360,8 @@ static int icnss_driver_event_register_driver(void *data) if (ret) goto out; + set_bit(ICNSS_DRIVER_LOADING, &penv->state); + reinit_completion(&penv->driver_probed); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = penv->ops->probe(&penv->pdev->dev); probe_cnt++; @@ -2359,9 +2371,13 @@ static int icnss_driver_event_register_driver(void *data) if (ret) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, penv->state, probe_cnt); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + complete(&penv->driver_probed); goto power_off; } + complete(&penv->driver_probed); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); set_bit(ICNSS_DRIVER_PROBED, &penv->state); return 0; @@ -2584,6 +2600,13 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && + test_bit(ICNSS_DRIVER_LOADING, &priv->state)) { + if (!wait_for_completion_timeout(&priv->driver_probed, + PROBE_TIMEOUT)) + icnss_pr_err("wlan driver probe timeout\n"); + } + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed) { ret = wlfw_send_modem_shutdown_msg(); if (ret) @@ -3980,6 +4003,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) continue; case ICNSS_DRIVER_UNLOADING: seq_puts(s, "DRIVER UNLOADING"); + continue; + case ICNSS_DRIVER_LOADING: + seq_puts(s, "WLAN DRIVER LOADING"); } seq_printf(s, "UNKNOWN-%d", i); @@ -4651,6 +4677,8 @@ static int icnss_probe(struct platform_device *pdev) penv = priv; + init_completion(&priv->driver_probed); + icnss_pr_info("Platform driver probed successfully\n"); return 0; @@ -4673,6 +4701,8 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); + complete_all(&penv->driver_probed); + icnss_modem_ssr_unregister_notifier(penv); destroy_ramdump_device(penv->msa0_dump_dev); From ab8f63420ca818ca92a85bf13db3711d2c936d26 Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Fri, 8 Feb 2019 15:46:53 +0530 Subject: [PATCH 03/17] icnss: Add Api to Block/Unblock modem shutdown Add API to Block/Unblock modem graceful shutdown. Change-Id: I69b061fc7d25762b2c36d9590802addfc170f91f Signed-off-by: Sandeep Singh --- drivers/soc/qcom/icnss.c | 49 ++++++++++++++++++++++++---------------- include/soc/qcom/icnss.h | 9 ++------ 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index f1eeb66ed80a..454a897c19ab 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -301,7 +301,7 @@ enum icnss_driver_state { ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, - ICNSS_DRIVER_LOADING, + ICNSS_BLOCK_SHUTDOWN, }; struct ce_irq_list { @@ -494,7 +494,7 @@ static struct icnss_priv { u8 requesting_sub_system; u16 line_number; char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; - struct completion driver_probed; + struct completion unblock_shutdown; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -1182,6 +1182,21 @@ bool icnss_is_fw_ready(void) } EXPORT_SYMBOL(icnss_is_fw_ready); +void icnss_block_shutdown(bool status) +{ + if (!penv) + return; + + if (status) { + set_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + reinit_completion(&penv->unblock_shutdown); + } else { + clear_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + complete(&penv->unblock_shutdown); + } +} +EXPORT_SYMBOL(icnss_block_shutdown); + bool icnss_is_fw_down(void) { if (!penv) @@ -2207,8 +2222,7 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) icnss_hw_power_on(priv); - set_bit(ICNSS_DRIVER_LOADING, &priv->state); - reinit_completion(&penv->driver_probed); + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = priv->ops->probe(&priv->pdev->dev); probe_cnt++; @@ -2218,13 +2232,11 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) if (ret < 0) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, priv->state, probe_cnt); - complete(&penv->driver_probed); - clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + icnss_block_shutdown(false); goto out; } - complete(&penv->driver_probed); - clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &priv->state); return 0; @@ -2360,8 +2372,7 @@ static int icnss_driver_event_register_driver(void *data) if (ret) goto out; - set_bit(ICNSS_DRIVER_LOADING, &penv->state); - reinit_completion(&penv->driver_probed); + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = penv->ops->probe(&penv->pdev->dev); probe_cnt++; @@ -2371,13 +2382,11 @@ static int icnss_driver_event_register_driver(void *data) if (ret) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, penv->state, probe_cnt); - clear_bit(ICNSS_DRIVER_LOADING, &penv->state); - complete(&penv->driver_probed); + icnss_block_shutdown(false); goto power_off; } - complete(&penv->driver_probed); - clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &penv->state); return 0; @@ -2601,8 +2610,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, return NOTIFY_OK; if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && - test_bit(ICNSS_DRIVER_LOADING, &priv->state)) { - if (!wait_for_completion_timeout(&priv->driver_probed, + test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { + if (!wait_for_completion_timeout(&priv->unblock_shutdown, PROBE_TIMEOUT)) icnss_pr_err("wlan driver probe timeout\n"); } @@ -4004,8 +4013,8 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_DRIVER_UNLOADING: seq_puts(s, "DRIVER UNLOADING"); continue; - case ICNSS_DRIVER_LOADING: - seq_puts(s, "WLAN DRIVER LOADING"); + case ICNSS_BLOCK_SHUTDOWN: + seq_puts(s, "BLOCK SHUTDOWN"); } seq_printf(s, "UNKNOWN-%d", i); @@ -4677,7 +4686,7 @@ static int icnss_probe(struct platform_device *pdev) penv = priv; - init_completion(&priv->driver_probed); + init_completion(&priv->unblock_shutdown); icnss_pr_info("Platform driver probed successfully\n"); @@ -4701,7 +4710,7 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); - complete_all(&penv->driver_probed); + complete_all(&penv->unblock_shutdown); icnss_modem_ssr_unregister_notifier(penv); diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 85ec8beb3157..010f29db8d48 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -157,10 +157,5 @@ extern bool icnss_is_rejuvenate(void); extern int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len); extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num); extern int icnss_trigger_recovery(struct device *dev); -extern void cnss_set_cc_source(enum cnss_cc_src cc_source); -extern enum cnss_cc_src cnss_get_cc_source(void); -extern int icnss_get_driver_load_cnt(void); -extern void icnss_increment_driver_load_cnt(void); -extern void icnss_set_cc_source(enum cnss_cc_src cc_source); -extern enum cnss_cc_src icnss_get_cc_source(void); +extern void icnss_block_shutdown(bool status); #endif /* _ICNSS_WLAN_H_ */ From b55c37ac6febb70739af96dadd4168a9295f6956 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Wed, 2 Jan 2019 20:55:34 +0530 Subject: [PATCH 04/17] msm: ice: check for crypto engine availability There can be many ice instances present in dtsi file but not all of them will be initialized by storage driver. Check if crypto instance is initialized before setting it up for data encryption/decryption usage. Change-Id: I7c9227007474052513b277dec5963a973781c524 Signed-off-by: Neeraj Soni --- drivers/crypto/msm/ice.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 68b6a26f00b8..64ddedeb2cca 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1729,7 +1729,7 @@ int qcom_ice_setup_ice_hw(const char *storage_type, int enable) if (ice_dev == ERR_PTR(-EPROBE_DEFER)) return -EPROBE_DEFER; - if (!ice_dev) + if (!ice_dev || (ice_dev->is_ice_enabled == false)) return ret; if (enable) From ed93ca6232dfd3182bbc99abdb254ac159af9301 Mon Sep 17 00:00:00 2001 From: Vignesh Kulothungan Date: Thu, 28 Feb 2019 14:55:05 -0800 Subject: [PATCH 05/17] msm: asm: validate ADSP data before access Validate buffer index obtained from ADSP token before using it. CRs-Fixed: 2372302 Change-Id: I5c3b1634bd08b516844638dd67f726a882edfc17 Signed-off-by: Vignesh Kulothungan --- sound/soc/msm/qdsp6v2/q6asm.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index de2cc07a4ab0..8ec3af00028d 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1948,6 +1948,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->dest_port); if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) && (data->opcode != ASM_DATA_EVENT_EOS) && + (data->opcode != ASM_SESSION_EVENTX_OVERFLOW) && (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) { if (payload == NULL) { pr_err("%s: payload is null\n", __func__); @@ -2130,6 +2131,17 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } spin_lock_irqsave(&port->dsp_lock, dsp_flags); buf_index = asm_token._token.buf_index; + if (buf_index < 0 || + buf_index >= port->max_buf_cnt) { + pr_err("%s: Invalid buffer index %u\n", + __func__, buf_index); + spin_unlock_irqrestore(&port->dsp_lock, + dsp_flags); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); + return -EINVAL; + } if (lower_32_bits(port->buf[buf_index].phys) != payload[0] || msm_audio_populate_upper_32_bits( @@ -2220,6 +2232,16 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } spin_lock_irqsave(&port->dsp_lock, dsp_flags); buf_index = asm_token._token.buf_index; + if (buf_index < 0 || buf_index >= port->max_buf_cnt) { + pr_err("%s: Invalid buffer index %u\n", + __func__, buf_index); + spin_unlock_irqrestore(&port->dsp_lock, + dsp_flags); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); + return -EINVAL; + } port->buf[buf_index].used = 0; if (lower_32_bits(port->buf[buf_index].phys) != payload[READDONE_IDX_BUFADD_LSW] || From 920b58ced94bfba727cc09a786449f37280b8e03 Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Tue, 5 Mar 2019 16:00:21 +0530 Subject: [PATCH 06/17] dsp: q6voice: Check size of shared memory buffer before access Check buffer size in qdsp_cvs_callback before access in ul_pkt. Change-Id: Ic19994b46086709231656ec747d2df988b7a512f Signed-off-by: Vatsal Bucha --- sound/soc/msm/qdsp6v2/q6voice.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c index 69189140c936..3193dd0de140 100644 --- a/sound/soc/msm/qdsp6v2/q6voice.c +++ b/sound/soc/msm/qdsp6v2/q6voice.c @@ -6782,6 +6782,11 @@ static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv) cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data; if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) { + if (v->shmem_info.sh_buf.buf[1].size < + ((3 * sizeof(uint32_t)) + cvs_voc_pkt[2])) { + pr_err("%s: invalid voc pkt size\n", __func__); + return -EINVAL; + } /* cvs_voc_pkt[0] contains tx timestamp */ common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3], cvs_voc_pkt[2], From 950b66256c03a0c40f4304be1626a3a693597347 Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Tue, 12 Feb 2019 17:18:18 +0800 Subject: [PATCH 07/17] asoc: check payload length against structure size Payload length must exceed structure size. Otherwise, it may lead to out-of-boundary memory access. Change-Id: I090de5116ab04a4ca2b9c485e17617fe9e861ad5 Signed-off-by: Xiaojun Sang --- sound/soc/msm/qdsp6v2/msm-qti-pp-config.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index 29a5fd18081a..6f4653a07dad 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1020,6 +1020,13 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, } event_data = (struct msm_adsp_event_data *)payload; + if (event_data->payload_len < sizeof(struct msm_adsp_event_data)) { + pr_err("%s: event_data size of %x is less than expected.\n", + __func__, event_data->payload_len); + ret = -EINVAL; + goto done; + } + kctl->info(kctl, &kctl_info); if (event_data->payload_len > From ea2ee83c9247d94f466e532906bb16ae37e4657b Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Fri, 19 Oct 2018 10:06:28 -0700 Subject: [PATCH 08/17] perf: Cancel the mux hrtimer during CPU hotplug to avoid migration The current design of hrtimers migrates the pinned timers to a different CPU upon its hotplug. However, perf-core needs to maintain the mux-hrtimers on a per CPU basis. That is, each hrtimer carries the context for that particular CPU and would lose this context if it gets migrated to a different CPU. As a result, cancel the hrtimer for the CPU that's about to go down and restart it (if required) when the perf-events are being created. Change-Id: I7a1d0456208855e3a99a7d49e59c6dae811d146e Signed-off-by: Raghavendra Rao Ananta [mojha@codeaurora.org: Resolved merge conflict and added missing `cpuctx` variable to avoid build failure] Signed-off-by: Mukesh Ojha --- include/linux/perf_event.h | 2 +- kernel/events/core.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f501b8c0de4e..efce166a9f17 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -231,7 +231,7 @@ struct pmu { int capabilities; int * __percpu pmu_disable_count; - struct perf_cpu_context * __percpu pmu_cpu_context; + struct perf_cpu_context __percpu *pmu_cpu_context; atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */ int task_ctx_nr; int hrtimer_interval_ms; diff --git a/kernel/events/core.c b/kernel/events/core.c index a8f984b4fcff..3e6e5eb3e4d2 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9654,13 +9654,26 @@ static void __perf_event_stop_swclock(void *__info) static void perf_event_exit_cpu_context(int cpu) { + struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; + unsigned long flags; struct pmu *pmu; int idx; idx = srcu_read_lock(&pmus_srcu); list_for_each_entry_rcu(pmu, &pmus, entry) { - ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx; + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); + ctx = &cpuctx->ctx; + + /* Cancel the mux hrtimer to avoid CPU migration */ + if (pmu->task_ctx_nr != perf_sw_context) { + raw_spin_lock_irqsave(&cpuctx->hrtimer_lock, flags); + hrtimer_cancel(&cpuctx->hrtimer); + cpuctx->hrtimer_active = 0; + raw_spin_unlock_irqrestore(&cpuctx->hrtimer_lock, + flags); + } + mutex_lock(&ctx->mutex); /* * If keeping events across hotplugging is supported, do not From f0cc7ca31096f58a28ab15dce1f522023857f5ee Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Tue, 12 Feb 2019 13:28:15 +0530 Subject: [PATCH 09/17] qdsp6v2: q6usm: Check size of payload before access Check size of payload array before access in q6usm_callback. Change-Id: Id0c85209a053f9dfdb53133aeb6b2510ecf18eb8 Signed-off-by: Vatsal Bucha --- drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c | 21 +++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c index 334e705ca8f1..085f68b22638 100644 --- a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c +++ b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -567,6 +567,11 @@ static int32_t q6usm_callback(struct apr_client_data *data, void *priv) } if (data->opcode == APR_BASIC_RSP_RESULT) { + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size[%d]\n", __func__, + data->payload_size); + return -EINVAL; + } /* status field check */ if (payload[1]) { pr_err("%s: wrong response[%d] on cmd [%d]\n", @@ -630,6 +635,14 @@ static int32_t q6usm_callback(struct apr_client_data *data, void *priv) opcode = Q6USM_EVENT_READ_DONE; spin_lock_irqsave(&port->dsp_lock, dsp_flags); + if (data->payload_size < + (sizeof(uint32_t)*(READDONE_IDX_STATUS + 1))) { + pr_err("%s: Invalid payload size for READDONE[%d]\n", + __func__, data->payload_size); + spin_unlock_irqrestore(&port->dsp_lock, + dsp_flags); + return -EINVAL; + } if (payload[READDONE_IDX_STATUS]) { pr_err("%s: wrong READDONE[%d]; token[%d]\n", __func__, @@ -675,6 +688,12 @@ static int32_t q6usm_callback(struct apr_client_data *data, void *priv) struct us_port_data *port = &usc->port[IN]; opcode = Q6USM_EVENT_WRITE_DONE; + if (data->payload_size < + (sizeof(uint32_t)*(WRITEDONE_IDX_STATUS + 1))) { + pr_err("%s: Invalid payload size for WRITEDONE[%d]\n", + __func__, data->payload_size); + return -EINVAL; + } if (payload[WRITEDONE_IDX_STATUS]) { pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n", __func__, From 9d3ba87f26263728d62e95c0435db642c0b081df Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Thu, 28 Feb 2019 18:03:17 +0530 Subject: [PATCH 10/17] drivers: soc: qcom: Added check to avoid opening multiple instance Opening of multiple instance of voice_svc user space from app will lead to pointer deference of private data within apr callback. As multi-instance not supported added check to deny open() from user space if previous instance hasn't been closed. Change-Id: Ia5ef16c69a517760fc9d45530a8a41a333fa2a21 Signed-off-by: Ajit Pandey --- drivers/soc/qcom/qdsp6v2/voice_svc.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index f01ab2499a75..0a49a322c9da 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -68,8 +68,9 @@ static void *dummy_q6_mvm; static void *dummy_q6_cvs; dev_t device_num; +static struct mutex session_lock; static spinlock_t voicesvc_lock; -static bool is_released; +static bool is_released = 1; static int voice_svc_dummy_reg(void); static int voice_svc_dummy_dereg(void); @@ -645,14 +646,23 @@ static int voice_svc_dummy_dereg(void) static int voice_svc_open(struct inode *inode, struct file *file) { struct voice_svc_prvt *prtd = NULL; + int ret = 0; pr_debug("%s\n", __func__); + mutex_lock(&session_lock); + if (is_released == 0) { + pr_err("%s: Access denied to device\n", __func__); + ret = -EBUSY; + goto done; + } + prtd = kmalloc(sizeof(struct voice_svc_prvt), GFP_KERNEL); if (prtd == NULL) { pr_err("%s: kmalloc failed\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto done; } memset(prtd, 0, sizeof(struct voice_svc_prvt)); @@ -676,7 +686,9 @@ static int voice_svc_open(struct inode *inode, struct file *file) voice_svc_dummy_reg(); reg_dummy_sess = 1; } - return 0; +done: + mutex_unlock(&session_lock); + return ret; } static int voice_svc_release(struct inode *inode, struct file *file) @@ -810,6 +822,7 @@ static int voice_svc_probe(struct platform_device *pdev) } pr_debug("%s: Device created\n", __func__); spin_lock_init(&voicesvc_lock); + mutex_init(&session_lock); goto done; add_err: @@ -832,6 +845,7 @@ static int voice_svc_remove(struct platform_device *pdev) kfree(voice_svc_dev->cdev); device_destroy(voice_svc_class, device_num); class_destroy(voice_svc_class); + mutex_destroy(&session_lock); unregister_chrdev_region(0, MINOR_NUMBER); return 0; From 279b0b023c43f4728a2790ab21cdff29520fd7dd Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Tue, 12 Feb 2019 13:07:27 +0530 Subject: [PATCH 11/17] qdsp6v2: q6usm: Check size of payload before access Check size of payload before access in q6usm_mmapcallback. Change-Id: Iff0672532c2ea40e7129237a92d8365d6b554cf2 Signed-off-by: Vatsal Bucha --- drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c index 085f68b22638..30a81ba39001 100644 --- a/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c +++ b/drivers/misc/qcom/qdsp6v2/ultrasound/q6usm.c @@ -507,6 +507,12 @@ static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv) uint32_t token; uint32_t *payload = data->payload; + if (data->payload_size < (2 * sizeof(uint32_t))) { + pr_err("%s: payload has invalid size[%d]\n", __func__, + data->payload_size); + return -EINVAL; + } + pr_debug("%s: ptr0[0x%x]; ptr1[0x%x]; opcode[0x%x]\n", __func__, payload[0], payload[1], data->opcode); pr_debug("%s: token[0x%x]; payload_size[%d]; src[%d]; dest[%d];\n", From a1b80321aed4f21460564ab19c40b46069dcecfd Mon Sep 17 00:00:00 2001 From: Rajesh Kemisetti Date: Fri, 10 Aug 2018 13:30:07 +0530 Subject: [PATCH 12/17] msm: kgsl: Limit log frequency in case of context count maxed out kgsl_context_init() prints error message continuously if a process tries to create more number of contexts that KGSL supports. This hogs CPU and might lead to watchdog timeout. Reduce this log frequency by using KGSL_DRV_ERR_RATELIMIT(). Change-Id: I7e3a5d3db41ab0c60d1b6b620cbcdef96d5c21a9 Signed-off-by: Rajesh Kemisetti --- drivers/gpu/msm/kgsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 95a32796a864..cd2466fd110f 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -542,7 +542,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, */ spin_lock(&proc_priv->ctxt_count_lock); if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) { - KGSL_DRV_ERR(device, + KGSL_DRV_ERR_RATELIMIT(device, "Per process context limit reached for pid %u", dev_priv->process_priv->pid); spin_unlock(&proc_priv->ctxt_count_lock); From 4fedfe5c4d9fc63e8c701e865850ab81259fa9a9 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Tue, 5 Mar 2019 17:16:54 +0530 Subject: [PATCH 13/17] soc: qcom: qmi_encdec: Restrict string length in decode The QMI TLV value for strings in a lot of qmi element info structures account for null terminated strings with MAX_LEN + 1. If a string is actually MAX_LEN + 1 length, this will cause an out of bounds access when the NULL character is appended in decoding. CR-Fixed: 2359244 Change-Id: I4d789bc6017ff58458f77fe875ca4e175a4f1357 Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh --- lib/qmi_encdec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c index 72b506bececc..9d5c446830ed 100644 --- a/lib/qmi_encdec.c +++ b/lib/qmi_encdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -710,8 +710,8 @@ static int qmi_decode_string_elem(struct elem_info *ei_array, void *buf_dst, decoded_bytes += rc; } - if (string_len > temp_ei->elem_len) { - pr_err("%s: String len %d > Max Len %d\n", + if (string_len >= temp_ei->elem_len) { + pr_err("%s: String len %d >= Max Len %d\n", __func__, string_len, temp_ei->elem_len); return -ETOOSMALL; } else if (string_len > tlv_len) { From 1b75396524935592d749e3a34cd46f0044e4c7b3 Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Tue, 12 Feb 2019 17:42:38 +0800 Subject: [PATCH 14/17] dsp: asm: validate payload size before access Payload size is not checked before payload access. Check it to avoid out-of-boundary memory access. Change-Id: Iaa39ee4ea5489bb5579e7b7d5dfada12d88c5809 Signed-off-by: Xiaojun Sang --- sound/soc/msm/qdsp6v2/q6asm.c | 250 ++++++++++++++++++++++++---------- 1 file changed, 176 insertions(+), 74 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 8ec3af00028d..79f1bc3be655 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1722,14 +1722,14 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) return 0; } - if (data->payload_size > sizeof(int)) { + if (data->payload_size >= 2 * sizeof(uint32_t)) { pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n", __func__, payload[0], payload[1], data->opcode, data->token, data->payload_size, data->src_port, data->dest_port, asm_token._token.session_id, dir); pr_debug("%s:Payload = [0x%x] status[0x%x]\n", __func__, payload[0], payload[1]); - } else if (data->payload_size == sizeof(int)) { + } else if (data->payload_size == sizeof(uint32_t)) { pr_debug("%s:ptr0[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n", __func__, payload[0], data->opcode, data->token, data->payload_size, data->src_port, @@ -1743,7 +1743,8 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) case ASM_CMD_SHARED_MEM_MAP_REGIONS: case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: case ASM_CMD_ADD_TOPOLOGIES: - if (payload[1] != 0) { + if (data->payload_size >= 2 * sizeof(uint32_t) + && payload[1] != 0) { pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n", __func__, payload[0], payload[1], asm_token._token.session_id); @@ -1761,8 +1762,12 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) wake_up(&ac->mem_wait); - dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n", + if (data->payload_size >= 2 * sizeof(uint32_t)) + dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n", __func__, payload[0], payload[1]); + else + dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n", + __func__, data->payload_size); break; default: pr_debug("%s: command[0x%x] not expecting rsp\n", @@ -1791,8 +1796,13 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) break; } case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{ - pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n", - __func__, payload[0], payload[1]); + if (data->payload_size >= 2 * sizeof(uint32_t)) + pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n", + __func__, payload[0], payload[1]); + else + pr_debug("%s: Payload size of %d is less than expected.\n", + __func__, data->payload_size); + spin_lock_irqsave(&port->dsp_lock, dsp_flags); if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) wake_up(&ac->mem_wait); @@ -1801,8 +1811,12 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) break; } default: - pr_debug("%s: command[0x%x]success [0x%x]\n", - __func__, payload[0], payload[1]); + if (data->payload_size >= 2 * sizeof(uint32_t)) + pr_debug("%s: command[0x%x]success [0x%x]\n", + __func__, payload[0], payload[1]); + else + pr_debug("%s: Payload size of %d is less than expected.\n", + __func__, data->payload_size); } if (ac->cb) ac->cb(data->opcode, data->token, @@ -1956,8 +1970,12 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) &(session[session_id].session_lock), flags); return -EINVAL; } - dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", - __func__, payload[0], payload[1], data->opcode); + if (data->payload_size >= 2 * sizeof(uint32_t)) + dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", + __func__, payload[0], payload[1], data->opcode); + else + dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n", + __func__, data->payload_size); } if (data->opcode == APR_BASIC_RSP_RESULT) { switch (payload[0]) { @@ -2002,32 +2020,40 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS: case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED: - pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n", - __func__, ac->session, - data->opcode, data->token, - payload[0], payload[1], - data->src_port, data->dest_port); - if (payload[1] != 0) { + if (data->payload_size >= + 2 * sizeof(uint32_t) && + payload[1] != 0) { + pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n", + __func__, ac->session, + data->opcode, data->token, + payload[0], payload[1], + data->src_port, data->dest_port); pr_err("%s: cmd = 0x%x returned error = 0x%x\n", - __func__, payload[0], payload[1]); + __func__, + payload[0], + payload[1]); if (wakeup_flag) { - if ((is_adsp_reg_event(payload[0]) >= - 0) || - (payload[0] == - ASM_STREAM_CMD_SET_PP_PARAMS_V2) || - (payload[0] == - ASM_STREAM_CMD_SET_PP_PARAMS_V3)) - atomic_set(&ac->cmd_state_pp, - payload[1]); + if ((is_adsp_reg_event(payload[0]) >= 0) + || (payload[0] == + ASM_STREAM_CMD_SET_PP_PARAMS_V2) + || (payload[0] == + ASM_STREAM_CMD_SET_PP_PARAMS_V3)) + atomic_set( + &ac->cmd_state_pp, + payload[1]); else - atomic_set(&ac->cmd_state, - payload[1]); + atomic_set( + &ac->cmd_state, + payload[1]); wake_up(&ac->cmd_wait); } spin_unlock_irqrestore( &(session[session_id].session_lock), flags); return 0; + } else { + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); } if ((is_adsp_reg_event(payload[0]) >= 0) || (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2) || @@ -2049,11 +2075,13 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) (uint32_t *)data->payload, ac->priv); break; case ASM_CMD_ADD_TOPOLOGIES: - pr_debug("%s:Payload = [0x%x]stat[0x%x]\n", - __func__, payload[0], payload[1]); - if (payload[1] != 0) { + if (data->payload_size >= + 2 * sizeof(uint32_t) && + payload[1] != 0) { + pr_debug("%s:Payload = [0x%x]stat[0x%x]\n", + __func__, payload[0], payload[1]); pr_err("%s: cmd = 0x%x returned error = 0x%x\n", - __func__, payload[0], payload[1]); + __func__, payload[0], payload[1]); if (wakeup_flag) { atomic_set(&ac->mem_state, payload[1]); wake_up(&ac->mem_wait); @@ -2072,8 +2100,12 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) (uint32_t *)data->payload, ac->priv); break; case ASM_DATA_EVENT_WATERMARK: { - pr_debug("%s: Watermark opcode[0x%x] status[0x%x]", - __func__, payload[0], payload[1]); + if (data->payload_size >= 2 * sizeof(uint32_t)) + pr_debug("%s: Watermark opcode[0x%x] status[0x%x]", + __func__, payload[0], payload[1]); + else + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); break; } case ASM_STREAM_CMD_GET_PP_PARAMS_V2: @@ -2085,11 +2117,17 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) /* error or malformed APR packet. Otherwise */ /* response will be returned as */ /* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */ - if (payload[1] != 0) { - pr_err("%s: ASM get param error = %d, resuming\n", - __func__, payload[1]); - rtac_make_asm_callback(ac->session, payload, + if (data->payload_size >= 2 * sizeof(uint32_t)) { + if (payload[1] != 0) { + pr_err("%s: ASM get param error = %d, resuming\n", + __func__, payload[1]); + rtac_make_asm_callback(ac->session, + payload, data->payload_size); + } + } else { + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); } break; case ASM_STREAM_CMD_REGISTER_PP_EVENTS: @@ -2097,11 +2135,16 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, ac->session, data->opcode, data->token, data->src_port, data->dest_port); - if (payload[1] != 0) - pr_err("%s: ASM get param error = %d, resuming\n", - __func__, payload[1]); - atomic_set(&ac->cmd_state_pp, payload[1]); - wake_up(&ac->cmd_wait); + if (data->payload_size >= 2 * sizeof(uint32_t)) { + if (payload[1] != 0) + pr_err("%s: ASM get param error = %d, resuming\n", + __func__, payload[1]); + atomic_set(&ac->cmd_state_pp, payload[1]); + wake_up(&ac->cmd_wait); + } else { + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); + } break; default: pr_debug("%s: command[0x%x] not expecting rsp\n", @@ -2117,9 +2160,13 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) switch (data->opcode) { case ASM_DATA_EVENT_WRITE_DONE_V2:{ struct audio_port_data *port = &ac->port[IN]; - dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]", - __func__, payload[0], payload[1], - data->token); + if (data->payload_size >= 2 * sizeof(uint32_t)) + dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]", + __func__, payload[0], payload[1], + data->token); + else + dev_err(ac->dev, "%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); if (ac->io_mode & SYNC_IO_MODE) { if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", @@ -2142,10 +2189,12 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) flags); return -EINVAL; } - if (lower_32_bits(port->buf[buf_index].phys) != - payload[0] || - msm_audio_populate_upper_32_bits( - port->buf[buf_index].phys) != payload[1]) { + if (data->payload_size >= 2 * sizeof(uint32_t) && + (lower_32_bits(port->buf[buf_index].phys) != + payload[0] || + msm_audio_populate_upper_32_bits( + port->buf[buf_index].phys) != + payload[1])) { pr_debug("%s: Expected addr %pK\n", __func__, &port->buf[buf_index].phys); pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n", @@ -2180,14 +2229,32 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } else if (generic_get_data) { generic_get_data->valid = 1; if (generic_get_data->is_inband) { - pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n", - __func__, payload[1], payload[2], payload[3]); - generic_get_data->size_in_ints = payload[3]>>2; - for (i = 0; i < payload[3]>>2; i++) { - generic_get_data->ints[i] = - payload[4+i]; - pr_debug("%s: ASM callback val %i = %i\n", - __func__, i, payload[4+i]); + if (data->payload_size >= 4 * sizeof(uint32_t)) + pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n", + __func__, + payload[1], + payload[2], + payload[3]); + else + pr_err("%s: payload size of %x is less than expected.\n", + __func__, + data->payload_size); + + if (data->payload_size >= + (4 + (payload[3]>>2)) + * sizeof(uint32_t)) { + generic_get_data->size_in_ints = + payload[3]>>2; + for (i = 0; i < payload[3]>>2; i++) { + generic_get_data->ints[i] = + payload[4+i]; + pr_debug("%s: ASM callback val %i = %i\n", + __func__, i, + payload[4+i]); + } + } else { + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); } pr_debug("%s: callback size in ints = %i\n", __func__, @@ -2284,11 +2351,17 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->src_port, data->dest_port); break; case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3: - dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n", - __func__, - payload[0], payload[1], payload[2]); - ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) | - payload[1]); + if (data->payload_size >= 3 * sizeof(uint32_t)) { + dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n", + __func__, + payload[0], payload[1], payload[2]); + ac->time_stamp = + (uint64_t)(((uint64_t)payload[2] << 32) | + payload[1]); + } else { + dev_err(ac->dev, "%s: payload size of %x is less than expected.n", + __func__, data->payload_size); + } if (atomic_cmpxchg(&ac->time_flag, 1, 0)) wake_up(&ac->time_wait); break; @@ -2298,10 +2371,14 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, ac->session, data->opcode, data->token, data->src_port, data->dest_port); - pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n", - __func__, - payload[0], payload[1], payload[2], - payload[3]); + if (data->payload_size >= 4 * sizeof(uint32_t)) + pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n", + __func__, + payload[0], payload[1], payload[2], + payload[3]); + else + pr_debug("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); break; case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2: q6asm_process_mtmx_get_param_rsp(ac, (void *) payload); @@ -2309,8 +2386,12 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_STREAM_PP_EVENT: case ASM_STREAM_CMD_ENCDEC_EVENTS: case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE: - pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]", - __func__, payload[0], payload[1]); + if (data->payload_size >= 2 * sizeof(uint32_t)) + pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]", + __func__, payload[0], payload[1]); + else + pr_debug("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); i = is_adsp_raise_event(data->opcode); if (i < 0) { spin_unlock_irqrestore( @@ -2322,6 +2403,14 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) * package is composed of event type + size + actual payload */ payload_size = data->payload_size; + if (payload_size > UINT_MAX - + sizeof(struct msm_adsp_event_data)) { + pr_err("%s: payload size = %d exceeds limit.\n", + __func__, payload_size); + spin_unlock(&(session[session_id].session_lock)); + return -EINVAL; + } + pp_event_package = kzalloc(payload_size + sizeof(struct msm_adsp_event_data), GFP_ATOMIC); @@ -2342,16 +2431,29 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) &(session[session_id].session_lock), flags); return 0; case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2: - pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n", - __func__, ac->session, payload[0], payload[2], - payload[1]); + if (data->payload_size >= 3 * sizeof(uint32_t)) + pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n", + __func__, ac->session, + payload[0], + payload[2], + payload[1]); + else + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); wake_up(&ac->cmd_wait); break; case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2: - pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n", - __func__, ac->session, payload[0], payload[2], + if (data->payload_size >= 3 * sizeof(uint32_t)) + pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n", + __func__, ac->session, + payload[0], payload[2], payload[1]); - if (payload[0] == 0) { + else + pr_err("%s: payload size of %x is less than expected.\n", + __func__, data->payload_size); + if (payload[0] == 0 && + data->payload_size >= + 2 * sizeof(uint32_t)) { atomic_set(&ac->cmd_state, 0); /* ignore msw, as a delay that large shouldn't happen */ ac->path_delay = payload[1]; From 1a649e08b2cda3e5a164d93bba7509cd03e0f882 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Sirasanagandla Date: Tue, 17 Oct 2017 18:00:55 +0800 Subject: [PATCH 15/17] msm: wlan: Update regulatory rules for JM As per regulatory master sheet, JM maps to FCC13 for 5GHz. For FCC13, there is no radar detect pattern. Therefore, Remove DFS flag for JM. CRs-Fixed: 2177739 Change-Id: I2dee046369ea4c3bd8feffbf97dbf40bea2137b6 Signed-off-by: Rajeev Kumar Sirasanagandla --- net/wireless/db.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index bc7a70a76685..326a6f29c6bd 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -579,8 +579,8 @@ country IT: DFS-ETSI country JM: DFS-FCC (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (5250 - 5330 @ 80), (24), AUTO-BW + (5490 - 5730 @ 160), (24) (5735 - 5835 @ 80), (30) # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) From 15c87d11b5af2203d79b639aba1b8952252a7480 Mon Sep 17 00:00:00 2001 From: kunleiz Date: Tue, 16 Apr 2019 17:46:37 +0800 Subject: [PATCH 16/17] lsm: check payload size validity before using it as array index Payload size validity is not checked before using it in array index. Check payload size to avoid out-of-boundary memory. Change-Id: Ic0b06bb331fc1753ff7543bb218ab12d6a4a3ca8 Signed-off-by: kunleiz --- include/sound/q6lsm.h | 4 +-- sound/soc/msm/qdsp6v2/msm-lsm-client.c | 45 +++++++++++++++++++++----- sound/soc/msm/qdsp6v2/q6lsm.c | 18 ++++++++--- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h index c046cd468b49..4600b0445955 100644 --- a/include/sound/q6lsm.h +++ b/include/sound/q6lsm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, 2019 Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,7 +26,7 @@ #define LSM_MAX_NUM_CHANNELS 8 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token, - uint32_t *payload, void *priv); + uint32_t *payload, uint16_t client_size, void *priv); struct lsm_sound_model { dma_addr_t phys; diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c index 5c4e145c2e31..9b0918cc579f 100644 --- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c +++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, 2019 Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -195,7 +195,8 @@ static int lsm_lab_buffer_sanity(struct lsm_priv *prtd, } static void lsm_event_handler(uint32_t opcode, uint32_t token, - void *payload, void *priv) + void *payload, uint16_t client_size, + void *priv) { unsigned long flags; struct lsm_priv *prtd = priv; @@ -263,6 +264,12 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, } case LSM_SESSION_EVENT_DETECTION_STATUS: + if (client_size < 3 * sizeof(uint8_t)) { + dev_err(rtd->dev, + "%s: client_size has invalid size[%d]\n", + __func__, client_size); + return; + } status = (uint16_t)((uint8_t *)payload)[0]; payload_size = (uint16_t)((uint8_t *)payload)[2]; index = 4; @@ -272,6 +279,12 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, break; case LSM_SESSION_EVENT_DETECTION_STATUS_V2: + if (client_size < 2 * sizeof(uint8_t)) { + dev_err(rtd->dev, + "%s: client_size has invalid size[%d]\n", + __func__, client_size); + return; + } status = (uint16_t)((uint8_t *)payload)[0]; payload_size = (uint16_t)((uint8_t *)payload)[1]; index = 2; @@ -281,6 +294,12 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, break; case LSM_SESSION_EVENT_DETECTION_STATUS_V3: + if (client_size < 2 * (sizeof(uint32_t) + sizeof(uint8_t))) { + dev_err(rtd->dev, + "%s: client_size has invalid size[%d]\n", + __func__, client_size); + return; + } event_ts_lsw = ((uint32_t *)payload)[0]; event_ts_msw = ((uint32_t *)payload)[1]; status = (uint16_t)((uint8_t *)payload)[8]; @@ -318,12 +337,22 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, prtd->event_status->payload_size = payload_size; if (likely(prtd->event_status)) { - memcpy(prtd->event_status->payload, - &((uint8_t *)payload)[index], - payload_size); - prtd->event_avail = 1; - spin_unlock_irqrestore(&prtd->event_lock, flags); - wake_up(&prtd->event_wait); + if (client_size >= (payload_size + index)) { + memcpy(prtd->event_status->payload, + &((uint8_t *)payload)[index], + payload_size); + prtd->event_avail = 1; + spin_unlock_irqrestore(&prtd->event_lock, + flags); + wake_up(&prtd->event_wait); + } else { + spin_unlock_irqrestore(&prtd->event_lock, + flags); + dev_err(rtd->dev, + "%s: Failed to copy memory with invalid size = %d\n", + __func__, payload_size); + return; + } } else { spin_unlock_irqrestore(&prtd->event_lock, flags); dev_err(rtd->dev, diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c index a0fa233bb71e..d926623eaa19 100644 --- a/sound/soc/msm/qdsp6v2/q6lsm.c +++ b/sound/soc/msm/qdsp6v2/q6lsm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -127,7 +127,8 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) if (data->opcode == LSM_DATA_EVENT_READ_DONE) { struct lsm_cmd_read_done read_done; token = data->token; - if (data->payload_size > sizeof(read_done)) { + if (data->payload_size > sizeof(read_done) || + data->payload_size < 6 * sizeof(payload[0])) { pr_err("%s: read done error payload size %d expected size %zd\n", __func__, data->payload_size, sizeof(read_done)); @@ -145,6 +146,7 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) if (client->cb) client->cb(data->opcode, data->token, (void *)&read_done, + sizeof(read_done), client->priv); return 0; } else if (data->opcode == APR_BASIC_RSP_RESULT) { @@ -171,6 +173,11 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) __func__, token, client->session); return -EINVAL; } + if (data->payload_size < 2 * sizeof(payload[0])) { + pr_err("%s: payload has invalid size[%d]\n", + __func__, data->payload_size); + return -EINVAL; + } client->cmd_err_code = payload[1]; if (client->cmd_err_code) pr_err("%s: cmd 0x%x failed status %d\n", @@ -191,7 +198,7 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) if (client->cb) client->cb(data->opcode, data->token, data->payload, - client->priv); + data->payload_size, client->priv); return 0; } @@ -1365,6 +1372,8 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) pr_debug("%s: SSR event received 0x%x, event 0x%x,\n" "proc 0x%x SID 0x%x\n", __func__, data->opcode, data->reset_event, data->reset_proc, sid); + if (sid < LSM_MIN_SESSION_ID || sid > LSM_MAX_SESSION_ID) + pr_err("%s: Invalid session %d\n", __func__, sid); lsm_common.common_client[sid].lsm_cal_phy_addr = 0; cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX, lsm_common.cal_data); @@ -1426,7 +1435,8 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) } if (client->cb) client->cb(data->opcode, data->token, - data->payload, client->priv); + data->payload, data->payload_size, + client->priv); return 0; } From 2cae403c69cc3ab30fc5133c6ceff87786910d30 Mon Sep 17 00:00:00 2001 From: Darshan Kumsi Srinivasa Date: Fri, 5 Oct 2018 17:30:52 +0530 Subject: [PATCH 17/17] msm: vidc: ignore processing responses in invalid state No need to process response messages from video hardware after device went into invalid state. Processing responses may result in use-after-free memory fault because client might free all the resources after error. Change-Id: I3bfb26e5aa52aba33b7b62cda7820dcbc5fe033f Signed-off-by: Darshan Kumsi Srinivasa --- drivers/media/platform/msm/vidc/venus_hfi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 1ec06cb07523..99903c0e7944 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -3717,7 +3717,12 @@ err_no_work: for (i = 0; !IS_ERR_OR_NULL(device->response_pkt) && i < num_responses; ++i) { struct msm_vidc_cb_info *r = &device->response_pkt[i]; - + if (!__core_in_valid_state(device)) { + dprintk(VIDC_ERR, + "Ignore responses from %d to %d as device is in invalid state", + (i + 1), num_responses); + break; + } device->callback(r->response_type, &r->response); }