msm: ultrasound: add verifications of some input parameters

Some security vulnerabilities were found.
To fix them, additional verifications of some input parameters
are required.

CRs-Fixed: 554575, 554560, 555030
Change-Id: Ie87a433bcda89c3e462cfd511c168e8306056020
Signed-off-by: Baruch Eruchimovitch <baruche@codeaurora.org>
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 1ea213a..01fcfd9 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -51,6 +51,11 @@
 #define Y_IND 1
 #define Z_IND 2
 
+/* Shared memory limits */
+/* max_buf_size = (port_size(65535*2) * port_num(8) * group_size(3) */
+#define USF_MAX_BUF_SIZE 3145680
+#define USF_MAX_BUF_NUM  32
+
 /* Place for opreation result, received from QDSP6 */
 #define APR_RESULT_IND 1
 
@@ -436,6 +441,15 @@
 	    (config == NULL))
 		return -EINVAL;
 
+	if ((config->buf_size == 0) ||
+	    (config->buf_size > USF_MAX_BUF_SIZE) ||
+	    (config->buf_num == 0) ||
+	    (config->buf_num > USF_MAX_BUF_NUM)) {
+		pr_err("%s: wrong params: buf_size=%d; buf_num=%d\n",
+		       __func__, config->buf_size, config->buf_num);
+		return -EINVAL;
+	}
+
 	data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
 	min_map_size = min(data_map_size, config->port_cnt);
 
@@ -748,6 +762,7 @@
 {
 	uint32_t timeout = 0;
 	struct us_detect_info_type detect_info;
+	struct usm_session_cmd_detect_info *p_allocated_memory = NULL;
 	struct usm_session_cmd_detect_info usm_detect_info;
 	struct usm_session_cmd_detect_info *p_usm_detect_info =
 						&usm_detect_info;
@@ -774,12 +789,13 @@
 		uint8_t *p_data = NULL;
 
 		detect_info_size += detect_info.params_data_size;
-		p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
-		if (p_usm_detect_info == NULL) {
+		 p_allocated_memory = kzalloc(detect_info_size, GFP_KERNEL);
+		if (p_allocated_memory == NULL) {
 			pr_err("%s: detect_info[%d] allocation failed\n",
 			       __func__, detect_info_size);
 			return -ENOMEM;
 		}
+		p_usm_detect_info = p_allocated_memory;
 		p_data = (uint8_t *)p_usm_detect_info +
 			sizeof(struct usm_session_cmd_detect_info);
 
@@ -789,7 +805,7 @@
 		if (rc) {
 			pr_err("%s: copy params from user; rc=%d\n",
 				__func__, rc);
-			kfree(p_usm_detect_info);
+			kfree(p_allocated_memory);
 			return -EFAULT;
 		}
 		p_usm_detect_info->algorithm_cfg_size =
@@ -806,9 +822,7 @@
 				    p_usm_detect_info,
 				    detect_info_size);
 	if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
-		if (detect_info_size >
-		    sizeof(struct usm_session_cmd_detect_info))
-			kfree(p_usm_detect_info);
+		kfree(p_allocated_memory);
 		return rc;
 	}
 
@@ -828,25 +842,24 @@
 					 USF_US_DETECT_UNDEF),
 					timeout);
 	/* In the case of timeout, "no US" is assumed */
-	if (rc < 0) {
+	if (rc < 0)
 		pr_err("%s: Getting US detection failed rc[%d]\n",
 		       __func__, rc);
-		return rc;
+	else {
+		usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+		detect_info.is_us =
+			(usf_xx->us_detect_type == USF_US_DETECT_YES);
+		rc = copy_to_user((void __user *)arg,
+				  &detect_info,
+				  sizeof(detect_info));
+		if (rc) {
+			pr_err("%s: copy detect_info to user; rc=%d\n",
+				__func__, rc);
+			rc = -EFAULT;
+		}
 	}
 
-	usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
-	detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
-	rc = copy_to_user((void __user *)arg,
-			  &detect_info,
-			  sizeof(detect_info));
-	if (rc) {
-		pr_err("%s: copy detect_info to user; rc=%d\n",
-			__func__, rc);
-		rc = -EFAULT;
-	}
-
-	if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
-		kfree(p_usm_detect_info);
+	kfree(p_allocated_memory);
 
 	return rc;
 } /* usf_set_us_detection */
@@ -947,16 +960,14 @@
 	if (rc)
 		return rc;
 
-	if (usf_xx->buffer_size && usf_xx->buffer_count) {
-		rc = q6usm_us_client_buf_alloc(
-					IN,
-					usf_xx->usc,
-					usf_xx->buffer_size,
-					usf_xx->buffer_count);
-		if (rc) {
-			(void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
-			return rc;
-		}
+	rc = q6usm_us_client_buf_alloc(
+				IN,
+				usf_xx->usc,
+				usf_xx->buffer_size,
+				usf_xx->buffer_count);
+	if (rc) {
+		(void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+		return rc;
 	}
 
 	rc = q6usm_dec_cfg_blk(usf_xx->usc,
@@ -1175,10 +1186,15 @@
 		return -EFAULT;
 	}
 
-	/* version_info.buf is pointer to place for the version string */
+	if (version_info.buf_size < sizeof(DRV_VERSION)) {
+		pr_err("%s: buf_size (%d) < version string size (%d)\n",
+			__func__, version_info.buf_size, sizeof(DRV_VERSION));
+		return -EINVAL;
+	}
+
 	rc = copy_to_user(version_info.pbuf,
 			  DRV_VERSION,
-			  version_info.buf_size);
+			  sizeof(DRV_VERSION));
 	if (rc) {
 		pr_err("%s: copy to version_info.pbuf; rc=%d\n",
 			__func__, rc);