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

Commit cdc117e0 authored by Charan Teja Reddy's avatar Charan Teja Reddy
Browse files

dma-buf: fix race while reading the dma_buf in dmabuffs_dname



The following race occurs while reading the dma_buf:
P1				P2
dma_buf_release()          dmabuffs_dname()[say from /proc/pid/fd/num]

			   read dmabuf stored in dentry->fsdata
Free the dmabuf object
			   Start accessing the dmabuf structure

As said above, we access the dmabuf structure after we free the dmabuf
object resulting into the below 'use-after-free' issue.
__mutex_lock_common+0x174/0x1020
mutex_lock_nested+0x40/0x50
dmabuffs_dname+0x48/0xc8
d_path+0x84/0x290
proc_pid_readlink+0xb4/0x1c8
vfs_readlink+0x128/0x130
do_readlinkat+0xc8/0x148
__arm64_sys_readlinkat+0x24/0x38
el0_svc_common+0xa4/0x178
el0_svc_handler+0x6c/0x88
el0_svc+0x8/0xc.

Fixes: bf93f26d ("UPSTREAM: dma-buf: add DMA_BUF_SET_NAME ioctls")
Change-Id: Ie0a833f185687f4cc7ab8189b17fde3516270572
Signed-off-by: default avatarCharan Teja Reddy <charante@codeaurora.org>
parent 196183c8
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <linux/list_sort.h>
#include <linux/hashtable.h>
#include <linux/mount.h>
#include <linux/dcache.h>

#include <uapi/linux/dma-buf.h>
#include <uapi/linux/magic.h>
@@ -69,18 +70,34 @@ struct dma_proc {

static struct dma_buf_list db_list;

static void dmabuf_dent_put(struct dma_buf *dmabuf)
{
	if (atomic_dec_and_test(&dmabuf->dent_count)) {
		kfree(dmabuf->name);
		kfree(dmabuf);
	}
}


static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
{
	struct dma_buf *dmabuf;
	char name[DMA_BUF_NAME_LEN];
	size_t ret = 0;

	spin_lock(&dentry->d_lock);
	dmabuf = dentry->d_fsdata;
	if (!dmabuf || !atomic_add_unless(&dmabuf->dent_count, 1, 0)) {
		spin_unlock(&dentry->d_lock);
		goto out;
	}
	spin_unlock(&dentry->d_lock);
	mutex_lock(&dmabuf->lock);
	if (dmabuf->name)
		ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
	mutex_unlock(&dmabuf->lock);

	dmabuf_dent_put(dmabuf);
out:
	return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
			     dentry->d_name.name, ret > 0 ? name : "");
}
@@ -107,6 +124,7 @@ static struct file_system_type dma_buf_fs_type = {
static int dma_buf_release(struct inode *inode, struct file *file)
{
	struct dma_buf *dmabuf;
	struct dentry *dentry = file->f_path.dentry;
	int dtor_ret = 0;

	if (!is_dma_buf_file(file))
@@ -114,6 +132,9 @@ static int dma_buf_release(struct inode *inode, struct file *file)

	dmabuf = file->private_data;

	spin_lock(&dentry->d_lock);
	dentry->d_fsdata = NULL;
	spin_unlock(&dentry->d_lock);
	BUG_ON(dmabuf->vmapping_counter);

	/*
@@ -145,8 +166,7 @@ static int dma_buf_release(struct inode *inode, struct file *file)
		reservation_object_fini(dmabuf->resv);

	module_put(dmabuf->owner);
	kfree(dmabuf->buf_name);
	kfree(dmabuf);
	dmabuf_dent_put(dmabuf);
	return 0;
}

@@ -604,6 +624,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
	dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
	dmabuf->buf_name = bufname;
	dmabuf->ktime = ktime_get();
	atomic_set(&dmabuf->dent_count, 1);

	if (!resv) {
		resv = (struct reservation_object *)&dmabuf[1];
+1 −0
Original line number Diff line number Diff line
@@ -445,6 +445,7 @@ struct dma_buf {
	struct list_head refs;
	dma_buf_destructor dtor;
	void *dtor_data;
	atomic_t dent_count;
};

/**