dma-buf: Cache the dma-buf inode number

Now that dma-buf has switched to handling its release from the
file_operations' release function to the dentry_operations' d_release
function there is a potential use-after-free when accessing the
buf_obj->file->f_inode as the path called by __fput eventually calls
__dentry_kill which frees the inode before calling the dentry_operations'
d_release function, so buf_obj->file->f_inode may no longer be valid.

It doesn't look like there is a clean way to check if the inode is valid.
For example using dentry->d_lock to look at the dentry inode would first
involve getting the dentry via a call to file_dentry which potentially
uses buf_obj->file->f_inode and it may no longer be valid.

It looks safer to simply cache the inode number since it is a useful value
to have as it identifies dma-buf objects.

KASAN log gave the following:
KASAN: use-after-free in dma_buf_debug_show+0x190/0x660
E : Read of size 8 at addr ffffff81051d7740 by task cat/19499
I Call trace:
I : dump_backtrace+0x0/0x2c8
I : show_stack+0x20/0x2c
I : dump_stack+0x154/0x1f4
I : print_address_description+0x84/0x580
I : __kasan_report+0x1b8/0x218
I : kasan_report+0x10/0x18
I : __asan_load8+0x90/0x98
I : dma_buf_debug_show+0x190/0x660
I : seq_read+0x2dc/0x830
I : full_proxy_read+0xbc/0x110
I : __vfs_read+0xd8/0x3d0
I : vfs_read+0x158/0x278
I : ksys_read+0x114/0x1e0
I : __arm64_sys_read+0x4c/0x5c
I : el0_svc_common+0x130/0x294
I : el0_svc_handler+0xdc/0xec
I : el0_svc+0x8/0xc
E : Allocated by task 912:
I : __kasan_kmalloc+0xfc/0x1b8
I : kasan_slab_alloc+0x14/0x1c
I : kmem_cache_alloc+0x320/0x3c4
I : new_inode_pseudo+0xbc/0x168
I : alloc_anon_inode+0x28/0x170
I : dma_buf_export+0x1e0/0x3ec
I : ion_dmabuf_alloc+0x168/0x1d4
I : ion_ioctl+0x24c/0x5c8
I : do_vfs_ioctl+0x55c/0xcb4
I : __arm64_sys_ioctl+0xa0/0xe4
I : el0_svc_common+0x130/0x294
I : el0_svc_handler+0xdc/0xec
I : el0_svc+0x8/0xc
E : Freed by task 40:
I : __kasan_slab_free+0x160/0x22c
I : kasan_slab_free+0x10/0x1c
I : slab_free_freelist_hook+0xdc/0x15c
I : kmem_cache_free+0xf8/0x350
I : i_callback+0x48/0x220
I : rcu_do_batch+0x2e8/0x594
I : nocb_cb_wait+0x158/0x930
I : rcu_nocb_cb_kthread+0x20/0x44
I : kthread+0x1ec/0x204

Change-Id: Ic3cfabf3524d2d34fe8b341e84f2ff259e4fad63
Signed-off-by: Liam Mark <lmark@codeaurora.org>
This commit is contained in:
Liam Mark 2020-08-28 17:32:50 -07:00
commit f03a6783a0
2 changed files with 5 additions and 3 deletions

View file

@ -63,8 +63,7 @@ static int dma_buf_invoke_dtor(struct dma_buf *dmabuf)
ret = dmabuf->dtor(dmabuf, dmabuf->dtor_data);
if (ret < 0)
pr_warn_ratelimited("Leaking dmabuf ino: %ld because destructor failed error: %d\n",
file_inode(dmabuf->file)->i_ino,
ret);
to_msm_dma_buf(dmabuf)->i_ino, ret);
}
return ret;
@ -587,6 +586,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
ret = PTR_ERR(file);
goto err_dmabuf;
}
msm_dma_buf->i_ino = file_inode(file)->i_ino;
file->f_mode |= FMODE_LSEEK;
dmabuf->file = file;
@ -1288,7 +1288,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
buf_obj->file->f_flags, buf_obj->file->f_mode,
file_count(buf_obj->file),
buf_obj->exp_name,
file_inode(buf_obj->file)->i_ino,
to_msm_dma_buf(buf_obj)->i_ino,
buf_obj->name ?: "");
robj = buf_obj->resv;

View file

@ -427,10 +427,12 @@ struct dma_buf {
* struct msm_dma_buf - Holds the meta data associated with a shared buffer
* object, as well as the buffer object.
* @refs: list entry for dma-buf reference tracking
* @i_ino: inode number
* @dma_buf: the shared buffer object
*/
struct msm_dma_buf {
struct list_head refs;
unsigned long i_ino;
struct dma_buf dma_buf;
};