From 16e535969ba0ddb07b93b3fd9e976d38678659d3 Mon Sep 17 00:00:00 2001 From: Kunlei Zhang Date: Wed, 23 Jan 2019 17:18:19 +0800 Subject: [PATCH] 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: Kunlei Zhang --- asoc/msm-lsm-client.c | 62 ++++++++++++++++++++++++++++++++++++------- dsp/q6lsm.c | 16 ++++++++--- include/dsp/q6lsm.h | 2 +- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index b101b377326d..3a5707e0de8d 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -196,7 +196,8 @@ static int lsm_lab_buffer_sanity(struct lsm_priv *prtd, } static void lsm_event_handler(uint32_t opcode, uint32_t token, - uint32_t *payload, void *priv) + uint32_t *payload, uint16_t client_size, + void *priv) { unsigned long flags; struct lsm_priv *prtd = priv; @@ -279,15 +280,27 @@ 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; dev_dbg(rtd->dev, "%s: event detect status = %d payload size = %d\n", __func__, status, payload_size); - break; + 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; @@ -297,6 +310,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]; @@ -310,6 +329,13 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, case LSM_SESSION_DETECTION_ENGINE_GENERIC_EVENT: { struct snd_lsm_event_status *tmp; + if (client_size < 2 * sizeof(uint16_t)) { + dev_err(rtd->dev, + "%s: client_size has invalid size[%d]\n", + __func__, client_size); + return; + } + status = ((uint16_t *)payload)[0]; payload_size = ((uint16_t *)payload)[1]; @@ -332,8 +358,16 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, prtd->det_event = tmp; prtd->det_event->status = status; prtd->det_event->payload_size = payload_size; - memcpy(prtd->det_event->payload, &((uint8_t *)payload)[4], - payload_size); + if (client_size >= payload_size + 4) { + memcpy(prtd->det_event->payload, + &((uint8_t *)payload)[4], payload_size); + } 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; + } prtd->event_avail = 1; spin_unlock_irqrestore(&prtd->event_lock, flags); wake_up(&prtd->event_wait); @@ -375,12 +409,20 @@ 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/dsp/q6lsm.c b/dsp/q6lsm.c index 6af7f6953507..c87a70181938 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -153,7 +153,8 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) 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)); @@ -171,6 +172,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) { @@ -198,6 +200,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", @@ -218,7 +225,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; } @@ -1791,6 +1798,8 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) "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); @@ -1855,7 +1864,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; } diff --git a/include/dsp/q6lsm.h b/include/dsp/q6lsm.h index 758bba0ec30e..e4a007f85356 100644 --- a/include/dsp/q6lsm.h +++ b/include/dsp/q6lsm.h @@ -21,7 +21,7 @@ #define LSM_API_VERSION_V3 3 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;