OSDN Git Service

lsm: check payload size validity before using it as array index
authorkunleiz <kunleiz@codeaurora.org>
Tue, 16 Apr 2019 09:46:37 +0000 (17:46 +0800)
committerkunleiz <kunleiz@codeaurora.org>
Wed, 17 Apr 2019 02:31:04 +0000 (10:31 +0800)
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>
include/sound/q6lsm.h
sound/soc/msm/qdsp6v2/msm-lsm-client.c
sound/soc/msm/qdsp6v2/q6lsm.c

index c046cd4..4600b04 100644 (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;
index 5c4e145..9b0918c 100644 (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,
index a0fa233..d926623 100644 (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;
 }