Merge "lsm: check payload size validity before using it as array index"
diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c
index f6a5698..213fe80 100644
--- a/asoc/msm-lsm-client.c
+++ b/asoc/msm-lsm-client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 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
@@ -195,7 +195,8 @@
}
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;
@@ -265,6 +266,12 @@
}
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;
@@ -274,6 +281,12 @@
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;
@@ -283,6 +296,12 @@
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];
@@ -321,12 +340,22 @@
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/dsp/q6lsm.c b/dsp/q6lsm.c
index a702661..7511c46 100644
--- a/dsp/q6lsm.c
+++ b/dsp/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
@@ -195,7 +195,8 @@
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));
@@ -213,6 +214,7 @@
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) {
@@ -238,6 +240,11 @@
__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",
@@ -258,7 +265,7 @@
if (client->cb)
client->cb(data->opcode, data->token, data->payload,
- client->priv);
+ data->payload_size, client->priv);
return 0;
}
@@ -1492,6 +1499,8 @@
"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);
apr_reset(lsm_common.apr);
lsm_common.apr = NULL;
atomic_set(&lsm_common.apr_users, 0);
@@ -1557,7 +1566,8 @@
}
if (client->cb)
client->cb(data->opcode, data->token,
- data->payload, client->priv);
+ data->payload, data->payload_size,
+ client->priv);
return 0;
}
diff --git a/include/dsp/q6lsm.h b/include/dsp/q6lsm.h
index efce3a6..be0e998 100644
--- a/include/dsp/q6lsm.h
+++ b/include/dsp/q6lsm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 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
@@ -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;