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 <kunleiz@codeaurora.org>
This commit is contained in:
kunleiz 2019-04-16 17:46:37 +08:00 committed by Gerrit - the friendly Code Review server
parent 1b75396524
commit 15c87d11b5
3 changed files with 53 additions and 14 deletions

View file

@ -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;

View file

@ -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,

View file

@ -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;
}