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

Commit 9835d736 authored by Jilai Wang's avatar Jilai Wang
Browse files

msm: npu: Allocate buffer per client for register read



In order to avoid double free or use after free the buffer
allocated while reading registers, it is needed to allocate the
buffer per client and free it in release function.

Change-Id: Ida806933819a6070164948e8abe034c41f8548fd
Signed-off-by: default avatarJilai Wang <jilaiw@codeaurora.org>
parent ddf7db4c
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -109,8 +109,6 @@ struct npu_debugfs_ctx {
	struct dentry *root;
	uint32_t reg_off;
	uint32_t reg_cnt;
	char *buf;
	size_t buf_len;
	uint8_t *log_buf;
	struct mutex log_lock;
	uint32_t log_num_bytes_buffered;
@@ -119,6 +117,12 @@ struct npu_debugfs_ctx {
	uint32_t log_buf_size;
};

struct npu_debugfs_reg_ctx {
	char *buf;
	size_t buf_len;
	struct npu_device *npu_dev;
};

struct npu_mbox {
	struct mbox_client client;
	struct mbox_chan *chan;
+35 −21
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
 */
static int npu_debug_open(struct inode *inode, struct file *file);
static int npu_debug_release(struct inode *inode, struct file *file);
static int npu_debug_reg_open(struct inode *inode, struct file *file);
static int npu_debug_reg_release(struct inode *inode, struct file *file);
static ssize_t npu_debug_reg_read(struct file *file,
		char __user *user_buf, size_t count, loff_t *ppos);
@@ -44,7 +45,7 @@ static ssize_t npu_debug_ctrl_write(struct file *file,
static struct npu_device *g_npu_dev;

static const struct file_operations npu_reg_fops = {
	.open = npu_debug_open,
	.open = npu_debug_reg_open,
	.release = npu_debug_reg_release,
	.read = npu_debug_reg_read,
};
@@ -87,16 +88,28 @@ static int npu_debug_release(struct inode *inode, struct file *file)
	return 0;
}

static int npu_debug_reg_release(struct inode *inode, struct file *file)
static int npu_debug_reg_open(struct inode *inode, struct file *file)
{
	struct npu_device *npu_dev = file->private_data;
	struct npu_debugfs_ctx *debugfs;
	struct npu_debugfs_reg_ctx *reg_ctx;

	debugfs = &npu_dev->debugfs_ctx;
	reg_ctx = kzalloc(sizeof(*reg_ctx), GFP_KERNEL);
	if (!reg_ctx)
		return -ENOMEM;

	kfree(debugfs->buf);
	debugfs->buf_len = 0;
	debugfs->buf = NULL;
	/* non-seekable */
	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
	reg_ctx->npu_dev = inode->i_private;
	file->private_data = reg_ctx;
	return 0;
}

static int npu_debug_reg_release(struct inode *inode, struct file *file)
{
	struct npu_debugfs_reg_ctx *reg_ctx = file->private_data;

	kfree(reg_ctx->buf);
	kfree(reg_ctx);
	file->private_data = NULL;
	return 0;
}

@@ -107,7 +120,8 @@ static int npu_debug_reg_release(struct inode *inode, struct file *file)
static ssize_t npu_debug_reg_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{
	struct npu_device *npu_dev = file->private_data;
	struct npu_debugfs_reg_ctx *reg_ctx = file->private_data;
	struct npu_device *npu_dev = reg_ctx->npu_dev;
	struct npu_debugfs_ctx *debugfs;
	size_t len;

@@ -116,16 +130,16 @@ static ssize_t npu_debug_reg_read(struct file *file,
	if (debugfs->reg_cnt == 0)
		return 0;

	if (!debugfs->buf) {
	if (!reg_ctx->buf) {
		char dump_buf[64];
		char *ptr;
		int cnt, tot, off;

		debugfs->buf_len = sizeof(dump_buf) *
		reg_ctx->buf_len = sizeof(dump_buf) *
			DIV_ROUND_UP(debugfs->reg_cnt, ROW_BYTES);
		debugfs->buf = kzalloc(debugfs->buf_len, GFP_KERNEL);
		reg_ctx->buf = kzalloc(reg_ctx->buf_len, GFP_KERNEL);

		if (!debugfs->buf)
		if (!reg_ctx->buf)
			return -ENOMEM;

		ptr = npu_dev->core_io.base + debugfs->reg_off;
@@ -139,28 +153,28 @@ static ssize_t npu_debug_reg_read(struct file *file,
			hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
					   ROW_BYTES, GROUP_BYTES, dump_buf,
					   sizeof(dump_buf), false);
			len = scnprintf(debugfs->buf + tot,
				debugfs->buf_len - tot, "0x%08x: %s\n",
			len = scnprintf(reg_ctx->buf + tot,
				reg_ctx->buf_len - tot, "0x%08x: %s\n",
				((int) (unsigned long) ptr) -
				((int) (unsigned long) npu_dev->core_io.base),
				dump_buf);

			ptr += ROW_BYTES;
			tot += len;
			if (tot >= debugfs->buf_len)
			if (tot >= reg_ctx->buf_len)
				break;
		}
		npu_disable_core_power(npu_dev);

		debugfs->buf_len = tot;
		reg_ctx->buf_len = tot;
	}

	if (*ppos >= debugfs->buf_len)
	if (*ppos >= reg_ctx->buf_len)
		return 0; /* done reading */

	len = min(count, debugfs->buf_len - (size_t) *ppos);
	NPU_DBG("read %zi %zi\n", count, debugfs->buf_len - (size_t) *ppos);
	if (copy_to_user(user_buf, debugfs->buf + *ppos, len)) {
	len = min(count, reg_ctx->buf_len - (size_t) *ppos);
	NPU_DBG("read %zi %zi\n", count, reg_ctx->buf_len - (size_t) *ppos);
	if (copy_to_user(user_buf, reg_ctx->buf + *ppos, len)) {
		NPU_ERR("failed to copy to user\n");
		return -EFAULT;
	}