فهرست منبع

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 <[email protected]>
Kunlei Zhang 6 سال پیش
والد
کامیت
16e535969b
3فایلهای تغییر یافته به همراه66 افزوده شده و 14 حذف شده
  1. 52 10
      asoc/msm-lsm-client.c
  2. 13 3
      dsp/q6lsm.c
  3. 1 1
      include/dsp/q6lsm.h

+ 52 - 10
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,

+ 13 - 3
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;
 }
 

+ 1 - 1
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;