Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88bdbaa0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wcnss: fix the potential memory leak and heap overflow"

parents dde07f28 0fb0b2a4
Loading
Loading
Loading
Loading
+51 −36
Original line number Diff line number Diff line
@@ -402,7 +402,6 @@ static struct {
	int	user_cal_available;
	u32	user_cal_rcvd;
	int	user_cal_exp_size;
	int	device_opened;
	int	iris_xo_mode_set;
	int	fw_vbatt_state;
	char	wlan_nv_macAddr[WLAN_MAC_ADDR_SIZE];
@@ -3400,14 +3399,6 @@ static int wcnss_node_open(struct inode *inode, struct file *file)
			return -EFAULT;
	}

	mutex_lock(&penv->dev_lock);
	penv->user_cal_rcvd = 0;
	penv->user_cal_read = 0;
	penv->user_cal_available = false;
	penv->user_cal_data = NULL;
	penv->device_opened = 1;
	mutex_unlock(&penv->dev_lock);

	return rc;
}

@@ -3416,7 +3407,7 @@ static ssize_t wcnss_wlan_read(struct file *fp, char __user
{
	int rc = 0;

	if (!penv || !penv->device_opened)
	if (!penv)
		return -EFAULT;

	rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
@@ -3453,55 +3444,66 @@ static ssize_t wcnss_wlan_write(struct file *fp, const char __user
			*user_buffer, size_t count, loff_t *position)
{
	int rc = 0;
	u32 size = 0;
	char *cal_data = NULL;

	if (!penv || !penv->device_opened || penv->user_cal_available)
	if (!penv || penv->user_cal_available)
		return -EFAULT;

	if (penv->user_cal_rcvd == 0 && count >= 4
			&& !penv->user_cal_data) {
		rc = copy_from_user((void *)&size, user_buffer, 4);
		if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
			pr_err(DEVICE " invalid size to write %d\n", size);
	if (!penv->user_cal_rcvd && count >= 4 && !penv->user_cal_exp_size) {
		mutex_lock(&penv->dev_lock);
		rc = copy_from_user((void *)&penv->user_cal_exp_size,
				    user_buffer, 4);
		if (!penv->user_cal_exp_size ||
		    penv->user_cal_exp_size > MAX_CALIBRATED_DATA_SIZE) {
			pr_err(DEVICE " invalid size to write %d\n",
			       penv->user_cal_exp_size);
			penv->user_cal_exp_size = 0;
			mutex_unlock(&penv->dev_lock);
			return -EFAULT;
		}

		rc += count;
		count -= 4;
		penv->user_cal_exp_size =  size;
		penv->user_cal_data = kmalloc(size, GFP_KERNEL);
		if (penv->user_cal_data == NULL) {
			pr_err(DEVICE " no memory to write\n");
			return -ENOMEM;
		}
		if (0 == count)
			goto exit;

	} else if (penv->user_cal_rcvd == 0 && count < 4)
		mutex_unlock(&penv->dev_lock);
		return count;
	} else if (!penv->user_cal_rcvd && count < 4) {
		return -EFAULT;
	}

	mutex_lock(&penv->dev_lock);
	if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
		(penv->user_cal_exp_size < count + penv->user_cal_rcvd)) {
		pr_err(DEVICE " invalid size to write %zu\n", count +
				penv->user_cal_rcvd);
		rc = -ENOMEM;
		goto exit;
		mutex_unlock(&penv->dev_lock);
		return -ENOMEM;
	}

	cal_data = kmalloc(count, GFP_KERNEL);
	if (!cal_data) {
		mutex_unlock(&penv->dev_lock);
		return -ENOMEM;
	}
	rc = copy_from_user((void *)penv->user_cal_data +
			penv->user_cal_rcvd, user_buffer, count);
	if (0 == rc) {

	rc = copy_from_user(cal_data, user_buffer, count);
	if (!rc) {
		memcpy(penv->user_cal_data + penv->user_cal_rcvd,
		       cal_data, count);
		penv->user_cal_rcvd += count;
		rc += count;
	}

	kfree(cal_data);
	if (penv->user_cal_rcvd == penv->user_cal_exp_size) {
		penv->user_cal_available = true;
		pr_info_ratelimited("wcnss: user cal written");
	}
	mutex_unlock(&penv->dev_lock);

exit:
	return rc;
}

static int wcnss_node_release(struct inode *inode, struct file *file)
{
	return 0;
}

static int wcnss_notif_cb(struct notifier_block *this, unsigned long code,
				void *ss_handle)
@@ -3560,6 +3562,7 @@ static const struct file_operations wcnss_node_fops = {
	.open = wcnss_node_open,
	.read = wcnss_wlan_read,
	.write = wcnss_wlan_write,
	.release = wcnss_node_release,
};

static struct miscdevice wcnss_misc = {
@@ -3587,6 +3590,13 @@ wcnss_wlan_probe(struct platform_device *pdev)
	}
	penv->pdev = pdev;

	penv->user_cal_data =
		devm_kzalloc(&pdev->dev, MAX_CALIBRATED_DATA_SIZE, GFP_KERNEL);
	if (!penv->user_cal_data) {
		dev_err(&pdev->dev, "Failed to alloc memory for cal data.\n");
		return -ENOMEM;
	}

	/* register sysfs entries */
	ret = wcnss_create_sysfs(&pdev->dev);
	if (ret) {
@@ -3607,6 +3617,11 @@ wcnss_wlan_probe(struct platform_device *pdev)
	mutex_init(&penv->pm_qos_mutex);
	init_waitqueue_head(&penv->read_wait);

	penv->user_cal_rcvd = 0;
	penv->user_cal_read = 0;
	penv->user_cal_exp_size = 0;
	penv->user_cal_available = false;

	/* Since we were built into the kernel we'll be called as part
	 * of kernel initialization.  We don't know if userspace
	 * applications are available to service PIL at this time