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

Commit b728ff01 authored by Sarada Prasanna Garnayak's avatar Sarada Prasanna Garnayak
Browse files

icnss: fix the memory and kernel info leak due to the race condition



The icnss register read/write debugfs entry can be accessed by
multiple user space thread. Memory allocation and deallocation
in the register read/write file operation leads to potential
memory leak during concurrency access of debugfs device file.

Add protection to avoid the memory leak and kernel information
leak due to the race condition in the register read/write ops.

CRs-Fixed: 2012572
Change-Id: I22c6af9a396c0df4e68f75702fc68a5dff5af032
Signed-off-by: default avatarSarada Prasanna Garnayak <sgarna@codeaurora.org>
parent 4bb2701f
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -440,6 +440,7 @@ static struct icnss_priv {
	u8 requesting_sub_system;
	u16 line_number;
	char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
	struct mutex dev_lock;
} *penv;

#ifdef CONFIG_ICNSS_DEBUG
@@ -4020,12 +4021,14 @@ static int icnss_regread_show(struct seq_file *s, void *data)
{
	struct icnss_priv *priv = s->private;

	mutex_lock(&priv->dev_lock);
	if (!priv->diag_reg_read_buf) {
		seq_puts(s, "Usage: echo <mem_type> <offset> <data_len> > <debugfs>/icnss/reg_read\n");

		if (!test_bit(ICNSS_FW_READY, &priv->state))
			seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");

		mutex_unlock(&priv->dev_lock);
		return 0;
	}

@@ -4039,6 +4042,7 @@ static int icnss_regread_show(struct seq_file *s, void *data)
	priv->diag_reg_read_len = 0;
	kfree(priv->diag_reg_read_buf);
	priv->diag_reg_read_buf = NULL;
	mutex_unlock(&priv->dev_lock);

	return 0;
}
@@ -4099,18 +4103,22 @@ static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
	    data_len > QMI_WLFW_MAX_DATA_SIZE_V01)
		return -EINVAL;

	mutex_lock(&priv->dev_lock);
	kfree(priv->diag_reg_read_buf);
	priv->diag_reg_read_buf = NULL;

	reg_buf = kzalloc(data_len, GFP_KERNEL);
	if (!reg_buf)
	if (!reg_buf) {
		mutex_unlock(&priv->dev_lock);
		return -ENOMEM;
	}

	ret = wlfw_athdiag_read_send_sync_msg(priv, reg_offset,
					      mem_type, data_len,
					      reg_buf);
	if (ret) {
		kfree(reg_buf);
		mutex_unlock(&priv->dev_lock);
		return ret;
	}

@@ -4118,6 +4126,7 @@ static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
	priv->diag_reg_read_mem_type = mem_type;
	priv->diag_reg_read_len = data_len;
	priv->diag_reg_read_buf = reg_buf;
	mutex_unlock(&priv->dev_lock);

	return count;
}
@@ -4397,6 +4406,7 @@ static int icnss_probe(struct platform_device *pdev)

	spin_lock_init(&priv->event_lock);
	spin_lock_init(&priv->on_off_lock);
	mutex_init(&priv->dev_lock);

	priv->event_wq = alloc_workqueue("icnss_driver_event", WQ_UNBOUND, 1);
	if (!priv->event_wq) {