]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
patches for 5.0
authorSasha Levin (Microsoft) <sashal@kernel.org>
Wed, 17 Apr 2019 17:16:22 +0000 (13:16 -0400)
committerSasha Levin (Microsoft) <sashal@kernel.org>
Wed, 17 Apr 2019 17:16:22 +0000 (13:16 -0400)
Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org>
queue-5.0/bpf-fix-use-after-free-in-bpf_evict_inode.patch [new file with mode: 0644]
queue-5.0/series

diff --git a/queue-5.0/bpf-fix-use-after-free-in-bpf_evict_inode.patch b/queue-5.0/bpf-fix-use-after-free-in-bpf_evict_inode.patch
new file mode 100644 (file)
index 0000000..5138775
--- /dev/null
@@ -0,0 +1,177 @@
+From b455bc192f9acbd783f0474f6563365cd5a8886c Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Mon, 25 Mar 2019 15:54:43 +0100
+Subject: bpf: fix use after free in bpf_evict_inode
+
+[ Upstream commit 1da6c4d9140cb7c13e87667dc4e1488d6c8fc10f ]
+
+syzkaller was able to generate the following UAF in bpf:
+
+  BUG: KASAN: use-after-free in lookup_last fs/namei.c:2269 [inline]
+  BUG: KASAN: use-after-free in path_lookupat.isra.43+0x9f8/0xc00 fs/namei.c:2318
+  Read of size 1 at addr ffff8801c4865c47 by task syz-executor2/9423
+
+  CPU: 0 PID: 9423 Comm: syz-executor2 Not tainted 4.20.0-rc1-next-20181109+
+  #110
+  Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
+  Google 01/01/2011
+  Call Trace:
+    __dump_stack lib/dump_stack.c:77 [inline]
+    dump_stack+0x244/0x39d lib/dump_stack.c:113
+    print_address_description.cold.7+0x9/0x1ff mm/kasan/report.c:256
+    kasan_report_error mm/kasan/report.c:354 [inline]
+    kasan_report.cold.8+0x242/0x309 mm/kasan/report.c:412
+    __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:430
+    lookup_last fs/namei.c:2269 [inline]
+    path_lookupat.isra.43+0x9f8/0xc00 fs/namei.c:2318
+    filename_lookup+0x26a/0x520 fs/namei.c:2348
+    user_path_at_empty+0x40/0x50 fs/namei.c:2608
+    user_path include/linux/namei.h:62 [inline]
+    do_mount+0x180/0x1ff0 fs/namespace.c:2980
+    ksys_mount+0x12d/0x140 fs/namespace.c:3258
+    __do_sys_mount fs/namespace.c:3272 [inline]
+    __se_sys_mount fs/namespace.c:3269 [inline]
+    __x64_sys_mount+0xbe/0x150 fs/namespace.c:3269
+    do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
+    entry_SYSCALL_64_after_hwframe+0x49/0xbe
+  RIP: 0033:0x457569
+  Code: fd b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7
+  48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff
+  ff 0f 83 cb b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00
+  RSP: 002b:00007fde6ed96c78 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
+  RAX: ffffffffffffffda RBX: 0000000000000005 RCX: 0000000000457569
+  RDX: 0000000020000040 RSI: 0000000020000000 RDI: 0000000000000000
+  RBP: 000000000072bf00 R08: 0000000020000340 R09: 0000000000000000
+  R10: 0000000000200000 R11: 0000000000000246 R12: 00007fde6ed976d4
+  R13: 00000000004c2c24 R14: 00000000004d4990 R15: 00000000ffffffff
+
+  Allocated by task 9424:
+    save_stack+0x43/0xd0 mm/kasan/kasan.c:448
+    set_track mm/kasan/kasan.c:460 [inline]
+    kasan_kmalloc+0xc7/0xe0 mm/kasan/kasan.c:553
+    __do_kmalloc mm/slab.c:3722 [inline]
+    __kmalloc_track_caller+0x157/0x760 mm/slab.c:3737
+    kstrdup+0x39/0x70 mm/util.c:49
+    bpf_symlink+0x26/0x140 kernel/bpf/inode.c:356
+    vfs_symlink+0x37a/0x5d0 fs/namei.c:4127
+    do_symlinkat+0x242/0x2d0 fs/namei.c:4154
+    __do_sys_symlink fs/namei.c:4173 [inline]
+    __se_sys_symlink fs/namei.c:4171 [inline]
+    __x64_sys_symlink+0x59/0x80 fs/namei.c:4171
+    do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
+    entry_SYSCALL_64_after_hwframe+0x49/0xbe
+
+  Freed by task 9425:
+    save_stack+0x43/0xd0 mm/kasan/kasan.c:448
+    set_track mm/kasan/kasan.c:460 [inline]
+    __kasan_slab_free+0x102/0x150 mm/kasan/kasan.c:521
+    kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:528
+    __cache_free mm/slab.c:3498 [inline]
+    kfree+0xcf/0x230 mm/slab.c:3817
+    bpf_evict_inode+0x11f/0x150 kernel/bpf/inode.c:565
+    evict+0x4b9/0x980 fs/inode.c:558
+    iput_final fs/inode.c:1550 [inline]
+    iput+0x674/0xa90 fs/inode.c:1576
+    do_unlinkat+0x733/0xa30 fs/namei.c:4069
+    __do_sys_unlink fs/namei.c:4110 [inline]
+    __se_sys_unlink fs/namei.c:4108 [inline]
+    __x64_sys_unlink+0x42/0x50 fs/namei.c:4108
+    do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
+    entry_SYSCALL_64_after_hwframe+0x49/0xbe
+
+In this scenario path lookup under RCU is racing with the final
+unlink in case of symlinks. As Linus puts it in his analysis:
+
+  [...] We actually RCU-delay the inode freeing itself, but
+  when we do the final iput(), the "evict()" function is called
+  synchronously. Now, the simple fix would seem to just RCU-delay
+  the kfree() of the symlink data in bpf_evict_inode(). Maybe
+  that's the right thing to do. [...]
+
+Al suggested to piggy-back on the ->destroy_inode() callback in
+order to implement RCU deferral there which can then kfree() the
+inode->i_link eventually right before putting inode back into
+inode cache. By reusing free_inode_nonrcu() from there we can
+avoid the need for our own inode cache and just reuse generic
+one as we currently do.
+
+And in-fact on top of all this we should just get rid of the
+bpf_evict_inode() entirely. This means truncate_inode_pages_final()
+and clear_inode() will then simply be called by the fs core via
+evict(). Dropping the reference should really only be done when
+inode is unhashed and nothing reachable anymore, so it's better
+also moved into the final ->destroy_inode() callback.
+
+Fixes: 0f98621bef5d ("bpf, inode: add support for symlinks and fix mtime/ctime")
+Reported-by: syzbot+fb731ca573367b7f6564@syzkaller.appspotmail.com
+Reported-by: syzbot+a13e5ead792d6df37818@syzkaller.appspotmail.com
+Reported-by: syzbot+7a8ba368b47fdefca61e@syzkaller.appspotmail.com
+Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
+Analyzed-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
+Acked-by: Al Viro <viro@zeniv.linux.org.uk>
+Link: https://lore.kernel.org/lkml/0000000000006946d2057bbd0eef@google.com/T/
+Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org>
+---
+ kernel/bpf/inode.c | 32 ++++++++++++++++++--------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
+index 2ada5e21dfa6..4a8f390a2b82 100644
+--- a/kernel/bpf/inode.c
++++ b/kernel/bpf/inode.c
+@@ -554,19 +554,6 @@ struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type typ
+ }
+ EXPORT_SYMBOL(bpf_prog_get_type_path);
+-static void bpf_evict_inode(struct inode *inode)
+-{
+-      enum bpf_type type;
+-
+-      truncate_inode_pages_final(&inode->i_data);
+-      clear_inode(inode);
+-
+-      if (S_ISLNK(inode->i_mode))
+-              kfree(inode->i_link);
+-      if (!bpf_inode_type(inode, &type))
+-              bpf_any_put(inode->i_private, type);
+-}
+-
+ /*
+  * Display the mount options in /proc/mounts.
+  */
+@@ -579,11 +566,28 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root)
+       return 0;
+ }
++static void bpf_destroy_inode_deferred(struct rcu_head *head)
++{
++      struct inode *inode = container_of(head, struct inode, i_rcu);
++      enum bpf_type type;
++
++      if (S_ISLNK(inode->i_mode))
++              kfree(inode->i_link);
++      if (!bpf_inode_type(inode, &type))
++              bpf_any_put(inode->i_private, type);
++      free_inode_nonrcu(inode);
++}
++
++static void bpf_destroy_inode(struct inode *inode)
++{
++      call_rcu(&inode->i_rcu, bpf_destroy_inode_deferred);
++}
++
+ static const struct super_operations bpf_super_ops = {
+       .statfs         = simple_statfs,
+       .drop_inode     = generic_delete_inode,
+       .show_options   = bpf_show_options,
+-      .evict_inode    = bpf_evict_inode,
++      .destroy_inode  = bpf_destroy_inode,
+ };
+ enum {
+-- 
+2.19.1
+
index f982f4124f636fe27af162313ea40b36df130f2b..eda872403bb87b078fbdc01321b59a3257e73875 100644 (file)
@@ -89,3 +89,4 @@ f2fs-fix-to-dirty-inode-for-i_mode-recovery.patch
 f2fs-fix-to-use-kvfree-instead-of-kzfree.patch
 f2fs-fix-to-add-refcount-once-page-is-tagged-pg_priv.patch
 include-linux-swap.h-use-offsetof-instead-of-custom-.patch
+bpf-fix-use-after-free-in-bpf_evict_inode.patch