fs: use-after-free in link_path_walk

112 views
Skip to first unread message

Dmitry Vyukov

unread,
Jan 22, 2016, 5:33:30 PM1/22/16
to Alexander Viro, linux-...@vger.kernel.org, LKML, Hugh Dickins, linu...@kvack.org, syzkaller, Kostya Serebryany, Alexander Potapenko, Sasha Levin, Eric Dumazet
Hello,

The following program triggers a use-after-free in link_path_walk:
https://gist.githubusercontent.com/dvyukov/fc0da4b914d607ba8129/raw/b761243c44106d74f2173745132c82d179cbdc58/gistfile1.txt

==================================================================
BUG: KASAN: use-after-free in link_path_walk+0xe13/0x1030 at addr
ffff88005f29d6e2
Read of size 1 by task syz-executor/29494
=============================================================================
BUG kmalloc-16 (Not tainted): kasan: bad access detected
-----------------------------------------------------------------------------

INFO: Allocated in shmem_symlink+0x18c/0x600 age=2 cpu=2 pid=29504
[< none >] __kmalloc_track_caller+0x28e/0x320 mm/slub.c:4068
[< none >] kmemdup+0x24/0x50 mm/util.c:113
[< none >] shmem_symlink+0x18c/0x600 mm/shmem.c:2548
[< none >] vfs_symlink+0x218/0x3a0 fs/namei.c:3997
[< inline >] SYSC_symlinkat fs/namei.c:4024
[< none >] SyS_symlinkat+0x1ab/0x230 fs/namei.c:4004
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185

INFO: Freed in shmem_evict_inode+0xa6/0x420 age=12 cpu=2 pid=29504
[< none >] kfree+0x2b7/0x2e0 mm/slub.c:3664
[< none >] shmem_evict_inode+0xa6/0x420 mm/shmem.c:705
[< none >] evict+0x22c/0x500 fs/inode.c:542
[< inline >] iput_final fs/inode.c:1477
[< none >] iput+0x45f/0x860 fs/inode.c:1504
[< none >] do_unlinkat+0x3c0/0x830 fs/namei.c:3939
[< inline >] SYSC_unlink fs/namei.c:3980
[< none >] SyS_unlink+0x1a/0x20 fs/namei.c:3978
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185

INFO: Slab 0xffffea00017ca700 objects=16 used=12 fp=0xffff88005f29d6e0
flags=0x5fffc0000004080
INFO: Object 0xffff88005f29d6e0 @offset=5856 fp=0xffff88005f29d310
CPU: 3 PID: 29494 Comm: syz-executor Tainted: G B 4.4.0+ #276
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
00000000ffffffff ffff88000056fa08 ffffffff82999e2d ffff88003e807900
ffff88005f29d6e0 ffff88005f29c000 ffff88000056fa38 ffffffff81757354
ffff88003e807900 ffffea00017ca700 ffff88005f29d6e0 ffff88005f29d6e2

Call Trace:
[<ffffffff8176092e>] __asan_report_load1_noabort+0x3e/0x40
mm/kasan/report.c:292
[<ffffffff817deb33>] link_path_walk+0xe13/0x1030 fs/namei.c:1913
[<ffffffff817df049>] path_lookupat+0x1a9/0x450 fs/namei.c:2120
[<ffffffff817e6aad>] filename_lookup+0x18d/0x370 fs/namei.c:2155
[<ffffffff817e6dd0>] user_path_at_empty+0x40/0x50 fs/namei.c:2393
[< inline >] user_path_at include/linux/namei.h:52
[<ffffffff8185ab29>] do_utimes+0x209/0x280 fs/utimes.c:169
[< inline >] SYSC_utimensat fs/utimes.c:200
[<ffffffff8185ada3>] SyS_utimensat+0xd3/0x130 fs/utimes.c:185
[<ffffffff86336c36>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
==================================================================

On commit 30f05309bde49295e02e45c7e615f73aa4e0ccc2 (Jan 20).

Al Viro

unread,
Jan 22, 2016, 6:08:28 PM1/22/16
to Dmitry Vyukov, linux-...@vger.kernel.org, LKML, Hugh Dickins, linu...@kvack.org, syzkaller, Kostya Serebryany, Alexander Potapenko, Sasha Levin, Eric Dumazet
On Fri, Jan 22, 2016 at 11:33:09PM +0100, Dmitry Vyukov wrote:
> Hello,
>
> The following program triggers a use-after-free in link_path_walk:
> https://gist.githubusercontent.com/dvyukov/fc0da4b914d607ba8129/raw/b761243c44106d74f2173745132c82d179cbdc58/gistfile1.txt

Hmm... Actually, I wonder if that had been triggerable since May. What
happens is that unlike struct inode itself, shmem info->symlink is
freed immediately, without an RCU delay. Easy to fix, fortunately...

Could you check if the patch below fixes that for you?

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index a43f41c..4d4780c 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -15,10 +15,7 @@ struct shmem_inode_info {
unsigned int seals; /* shmem seals */
unsigned long flags;
unsigned long alloced; /* data pages alloced to file */
- union {
- unsigned long swapped; /* subtotal assigned to swap */
- char *symlink; /* unswappable short symlink */
- };
+ unsigned long swapped; /* subtotal assigned to swap */
struct shared_policy policy; /* NUMA memory alloc policy */
struct list_head swaplist; /* chain of maybes on swap */
struct simple_xattrs xattrs; /* list of xattrs */
diff --git a/mm/shmem.c b/mm/shmem.c
index 38c5e72..440e2a7 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -701,8 +701,7 @@ static void shmem_evict_inode(struct inode *inode)
list_del_init(&info->swaplist);
mutex_unlock(&shmem_swaplist_mutex);
}
- } else
- kfree(info->symlink);
+ }

simple_xattrs_free(&info->xattrs);
WARN_ON(inode->i_blocks);
@@ -2549,13 +2548,12 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
info = SHMEM_I(inode);
inode->i_size = len-1;
if (len <= SHORT_SYMLINK_LEN) {
- info->symlink = kmemdup(symname, len, GFP_KERNEL);
- if (!info->symlink) {
+ inode->i_link = kmemdup(symname, len, GFP_KERNEL);
+ if (!inode->i_link) {
iput(inode);
return -ENOMEM;
}
inode->i_op = &shmem_short_symlink_operations;
- inode->i_link = info->symlink;
} else {
inode_nohighmem(inode);
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
@@ -3132,6 +3130,7 @@ static struct inode *shmem_alloc_inode(struct super_block *sb)
static void shmem_destroy_callback(struct rcu_head *head)
{
struct inode *inode = container_of(head, struct inode, i_rcu);
+ kfree(inode->i_link);
kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
}

Dmitry Vyukov

unread,
Feb 5, 2016, 8:33:28 AM2/5/16
to Al Viro, linux-...@vger.kernel.org, LKML, Hugh Dickins, linu...@kvack.org, syzkaller, Kostya Serebryany, Alexander Potapenko, Sasha Levin, Eric Dumazet
On Sat, Jan 23, 2016 at 12:08 AM, Al Viro <vi...@zeniv.linux.org.uk> wrote:
> On Fri, Jan 22, 2016 at 11:33:09PM +0100, Dmitry Vyukov wrote:
>> Hello,
>>
>> The following program triggers a use-after-free in link_path_walk:
>> https://gist.githubusercontent.com/dvyukov/fc0da4b914d607ba8129/raw/b761243c44106d74f2173745132c82d179cbdc58/gistfile1.txt
>
> Hmm... Actually, I wonder if that had been triggerable since May. What
> happens is that unlike struct inode itself, shmem info->symlink is
> freed immediately, without an RCU delay. Easy to fix, fortunately...
>
> Could you check if the patch below fixes that for you?

Yes, it fixes the crash for me.
Thanks
Reply all
Reply to author
Forward
0 new messages