2019-01-11 15:55:13

by syzbot

[permalink] [raw]
Subject: KASAN: use-after-free Read in seccomp_notify_release

Hello,

syzbot found the following crash on:

HEAD commit: 1bdbe2274920 Merge tag 'vfio-v5.0-rc2' of git://github.com..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=177ce96f400000
kernel config: https://syzkaller.appspot.com/x/.config?x=edf1c3031097c304
dashboard link: https://syzkaller.appspot.com/bug?extid=981c26489b2d1c6316ba
compiler: gcc (GCC) 9.0.0 20181231 (experimental)
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=134c5b9f400000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=1263027b400000

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: [email protected]

audit: type=1326 audit(1547207941.906:33): auid=4294967295 uid=0 gid=0
ses=4294967295 subj=_ pid=7929 comm="syz-executor201"
exe="/root/syz-executor201062921" sig=31 arch=c000003e syscall=202 compat=0
ip=0x446349 code=0x0
==================================================================
BUG: KASAN: use-after-free in __lock_acquire+0x3556/0x4a30
kernel/locking/lockdep.c:3215
Read of size 8 at addr ffff888098dd1280 by task syz-executor201/7925

CPU: 1 PID: 7925 Comm: syz-executor201 Not tainted 5.0.0-rc1+ #19
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+0x1db/0x2d0 lib/dump_stack.c:113
print_address_description.cold+0x7c/0x20d mm/kasan/report.c:187
kasan_report.cold+0x1b/0x40 mm/kasan/report.c:317
__asan_report_load8_noabort+0x14/0x20 mm/kasan/generic_report.c:135
__lock_acquire+0x3556/0x4a30 kernel/locking/lockdep.c:3215
lock_acquire+0x1db/0x570 kernel/locking/lockdep.c:3841
__mutex_lock_common kernel/locking/mutex.c:925 [inline]
__mutex_lock+0x12f/0x1670 kernel/locking/mutex.c:1072
mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:1087
seccomp_notify_release+0x54/0x270 kernel/seccomp.c:979
__fput+0x3c5/0xb10 fs/file_table.c:278
____fput+0x16/0x20 fs/file_table.c:309
task_work_run+0x1f4/0x2b0 kernel/task_work.c:113
tracehook_notify_resume include/linux/tracehook.h:188 [inline]
exit_to_usermode_loop+0x32a/0x3b0 arch/x86/entry/common.c:166
prepare_exit_to_usermode arch/x86/entry/common.c:197 [inline]
syscall_return_slowpath arch/x86/entry/common.c:268 [inline]
do_syscall_64+0x696/0x800 arch/x86/entry/common.c:293
entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x405451
Code: 75 14 b8 03 00 00 00 0f 05 48 3d 01 f0 ff ff 0f 83 94 17 00 00 c3 48
83 ec 08 e8 6a fc ff ff 48 89 04 24 b8 03 00 00 00 0f 05 <48> 8b 3c 24 48
89 c2 e8 b3 fc ff ff 48 89 d0 48 83 c4 08 48 3d 01
RSP: 002b:00007ffe221b1d60 EFLAGS: 00000293 ORIG_RAX: 0000000000000003
RAX: 0000000000000000 RBX: 0000000000000003 RCX: 0000000000405451
RDX: 0000000000000000 RSI: 0000000000000080 RDI: 0000000000000003
RBP: 00000000000003e8 R08: 00000000000003e8 R09: 0000000000000000
R10: 00007ffe221b1d70 R11: 0000000000000293 R12: 00000000006dac3c
R13: 0000000000000002 R14: 000000000000002d R15: 00000000006dac30

Allocated by task 7934:
save_stack+0x45/0xd0 mm/kasan/common.c:73
set_track mm/kasan/common.c:85 [inline]
__kasan_kmalloc mm/kasan/common.c:496 [inline]
__kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:469
kasan_kmalloc+0x9/0x10 mm/kasan/common.c:504
kmem_cache_alloc_trace+0x151/0x760 mm/slab.c:3609
kmalloc include/linux/slab.h:545 [inline]
kzalloc include/linux/slab.h:740 [inline]
seccomp_prepare_filter kernel/seccomp.c:451 [inline]
seccomp_prepare_user_filter kernel/seccomp.c:491 [inline]
seccomp_set_mode_filter kernel/seccomp.c:1257 [inline]
do_seccomp+0x941/0x2cc0 kernel/seccomp.c:1370
__do_sys_seccomp kernel/seccomp.c:1389 [inline]
__se_sys_seccomp kernel/seccomp.c:1386 [inline]
__x64_sys_seccomp+0x73/0xb0 kernel/seccomp.c:1386
do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290
entry_SYSCALL_64_after_hwframe+0x49/0xbe

Freed by task 7934:
save_stack+0x45/0xd0 mm/kasan/common.c:73
set_track mm/kasan/common.c:85 [inline]
__kasan_slab_free+0x102/0x150 mm/kasan/common.c:458
kasan_slab_free+0xe/0x10 mm/kasan/common.c:466
__cache_free mm/slab.c:3487 [inline]
kfree+0xcf/0x230 mm/slab.c:3806
seccomp_filter_free kernel/seccomp.c:565 [inline]
seccomp_filter_free kernel/seccomp.c:561 [inline]
seccomp_set_mode_filter kernel/seccomp.c:1311 [inline]
do_seccomp+0xda3/0x2cc0 kernel/seccomp.c:1370
__do_sys_seccomp kernel/seccomp.c:1389 [inline]
__se_sys_seccomp kernel/seccomp.c:1386 [inline]
__x64_sys_seccomp+0x73/0xb0 kernel/seccomp.c:1386
do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290
entry_SYSCALL_64_after_hwframe+0x49/0xbe

The buggy address belongs to the object at ffff888098dd1200
which belongs to the cache kmalloc-192 of size 192
The buggy address is located 128 bytes inside of
192-byte region [ffff888098dd1200, ffff888098dd12c0)
The buggy address belongs to the page:
page:ffffea0002637440 count:1 mapcount:0 mapping:ffff88812c3f0040
index:0xffff888098dd1e00
flags: 0x1fffc0000000200(slab)
raw: 01fffc0000000200 ffffea0002810748 ffffea0002614808 ffff88812c3f0040
raw: ffff888098dd1e00 ffff888098dd1000 000000010000000f 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
ffff888098dd1180: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
ffff888098dd1200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff888098dd1280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
^
ffff888098dd1300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888098dd1380: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
==================================================================


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at [email protected].

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with
syzbot.
syzbot can test patches for this bug, for details see:
https://goo.gl/tpsmEJ#testing-patches


2019-01-12 17:33:32

by Kees Cook

[permalink] [raw]
Subject: Re: KASAN: use-after-free Read in seccomp_notify_release

On Fri, Jan 11, 2019 at 7:53 AM syzbot
<[email protected]> wrote:
>
> Hello,
>
> syzbot found the following crash on:
>
> HEAD commit: 1bdbe2274920 Merge tag 'vfio-v5.0-rc2' of git://github.com..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=177ce96f400000
> kernel config: https://syzkaller.appspot.com/x/.config?x=edf1c3031097c304
> dashboard link: https://syzkaller.appspot.com/bug?extid=981c26489b2d1c6316ba
> compiler: gcc (GCC) 9.0.0 20181231 (experimental)
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=134c5b9f400000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=1263027b400000

Oh, interesting. And a working reproducer!

16 threads alternating between these two seccomp calls:

case 0:
struct sock_filter = { .code = BPF_RET, .k = 0x7ffffffe };
struct sock_fprog prog = { .len = 1, filter = &filter };
syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog);

case 1:
struct sock_filter = { .code = BPF_RET, };
struct sock_fprog prog = { .len = 1, filter = &filter };
syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
SECCOMP_FILTER_FLAG_TSYNC | SECCOMP_FILTER_FLAG_NEW_LISTENER,
&prog);


> IMPORTANT: if you fix the bug, please add the following tag to the commit:
> Reported-by: [email protected]
>
> audit: type=1326 audit(1547207941.906:33): auid=4294967295 uid=0 gid=0
> ses=4294967295 subj=_ pid=7929 comm="syz-executor201"
> exe="/root/syz-executor201062921" sig=31 arch=c000003e syscall=202 compat=0
> ip=0x446349 code=0x0
> ==================================================================
> BUG: KASAN: use-after-free in __lock_acquire+0x3556/0x4a30
> kernel/locking/lockdep.c:3215
> Read of size 8 at addr ffff888098dd1280 by task syz-executor201/7925
>
> CPU: 1 PID: 7925 Comm: syz-executor201 Not tainted 5.0.0-rc1+ #19
> 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+0x1db/0x2d0 lib/dump_stack.c:113
> print_address_description.cold+0x7c/0x20d mm/kasan/report.c:187
> kasan_report.cold+0x1b/0x40 mm/kasan/report.c:317
> __asan_report_load8_noabort+0x14/0x20 mm/kasan/generic_report.c:135
> __lock_acquire+0x3556/0x4a30 kernel/locking/lockdep.c:3215
> lock_acquire+0x1db/0x570 kernel/locking/lockdep.c:3841
> __mutex_lock_common kernel/locking/mutex.c:925 [inline]
> __mutex_lock+0x12f/0x1670 kernel/locking/mutex.c:1072
> mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:1087
> seccomp_notify_release+0x54/0x270 kernel/seccomp.c:979

Tycho, can you take a look at this? Maybe it's a bad interaction with TSYNC?

> __fput+0x3c5/0xb10 fs/file_table.c:278
> ____fput+0x16/0x20 fs/file_table.c:309
> task_work_run+0x1f4/0x2b0 kernel/task_work.c:113
> tracehook_notify_resume include/linux/tracehook.h:188 [inline]
> exit_to_usermode_loop+0x32a/0x3b0 arch/x86/entry/common.c:166
> prepare_exit_to_usermode arch/x86/entry/common.c:197 [inline]
> syscall_return_slowpath arch/x86/entry/common.c:268 [inline]
> do_syscall_64+0x696/0x800 arch/x86/entry/common.c:293
> entry_SYSCALL_64_after_hwframe+0x49/0xbe
> RIP: 0033:0x405451
> Code: 75 14 b8 03 00 00 00 0f 05 48 3d 01 f0 ff ff 0f 83 94 17 00 00 c3 48
> 83 ec 08 e8 6a fc ff ff 48 89 04 24 b8 03 00 00 00 0f 05 <48> 8b 3c 24 48
> 89 c2 e8 b3 fc ff ff 48 89 d0 48 83 c4 08 48 3d 01
> RSP: 002b:00007ffe221b1d60 EFLAGS: 00000293 ORIG_RAX: 0000000000000003
> RAX: 0000000000000000 RBX: 0000000000000003 RCX: 0000000000405451
> RDX: 0000000000000000 RSI: 0000000000000080 RDI: 0000000000000003
> RBP: 00000000000003e8 R08: 00000000000003e8 R09: 0000000000000000
> R10: 00007ffe221b1d70 R11: 0000000000000293 R12: 00000000006dac3c
> R13: 0000000000000002 R14: 000000000000002d R15: 00000000006dac30
>
> Allocated by task 7934:
> save_stack+0x45/0xd0 mm/kasan/common.c:73
> set_track mm/kasan/common.c:85 [inline]
> __kasan_kmalloc mm/kasan/common.c:496 [inline]
> __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:469
> kasan_kmalloc+0x9/0x10 mm/kasan/common.c:504
> kmem_cache_alloc_trace+0x151/0x760 mm/slab.c:3609
> kmalloc include/linux/slab.h:545 [inline]
> kzalloc include/linux/slab.h:740 [inline]
> seccomp_prepare_filter kernel/seccomp.c:451 [inline]
> seccomp_prepare_user_filter kernel/seccomp.c:491 [inline]
> seccomp_set_mode_filter kernel/seccomp.c:1257 [inline]
> do_seccomp+0x941/0x2cc0 kernel/seccomp.c:1370
> __do_sys_seccomp kernel/seccomp.c:1389 [inline]
> __se_sys_seccomp kernel/seccomp.c:1386 [inline]
> __x64_sys_seccomp+0x73/0xb0 kernel/seccomp.c:1386
> do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290
> entry_SYSCALL_64_after_hwframe+0x49/0xbe
>
> Freed by task 7934:
> save_stack+0x45/0xd0 mm/kasan/common.c:73
> set_track mm/kasan/common.c:85 [inline]
> __kasan_slab_free+0x102/0x150 mm/kasan/common.c:458
> kasan_slab_free+0xe/0x10 mm/kasan/common.c:466
> __cache_free mm/slab.c:3487 [inline]
> kfree+0xcf/0x230 mm/slab.c:3806
> seccomp_filter_free kernel/seccomp.c:565 [inline]
> seccomp_filter_free kernel/seccomp.c:561 [inline]
> seccomp_set_mode_filter kernel/seccomp.c:1311 [inline]
> do_seccomp+0xda3/0x2cc0 kernel/seccomp.c:1370
> __do_sys_seccomp kernel/seccomp.c:1389 [inline]
> __se_sys_seccomp kernel/seccomp.c:1386 [inline]
> __x64_sys_seccomp+0x73/0xb0 kernel/seccomp.c:1386
> do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290
> entry_SYSCALL_64_after_hwframe+0x49/0xbe
>
> The buggy address belongs to the object at ffff888098dd1200
> which belongs to the cache kmalloc-192 of size 192
> The buggy address is located 128 bytes inside of
> 192-byte region [ffff888098dd1200, ffff888098dd12c0)
> The buggy address belongs to the page:
> page:ffffea0002637440 count:1 mapcount:0 mapping:ffff88812c3f0040
> index:0xffff888098dd1e00
> flags: 0x1fffc0000000200(slab)
> raw: 01fffc0000000200 ffffea0002810748 ffffea0002614808 ffff88812c3f0040
> raw: ffff888098dd1e00 ffff888098dd1000 000000010000000f 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff888098dd1180: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> ffff888098dd1200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> > ffff888098dd1280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> ^
> ffff888098dd1300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff888098dd1380: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> ==================================================================
>
>
> ---
> This bug is generated by a bot. It may contain errors.
> See https://goo.gl/tpsmEJ for more information about syzbot.
> syzbot engineers can be reached at [email protected].
>
> syzbot will keep track of this bug report. See:
> https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with
> syzbot.
> syzbot can test patches for this bug, for details see:
> https://goo.gl/tpsmEJ#testing-patches



--
Kees Cook

2019-01-12 19:14:09

by Tycho Andersen

[permalink] [raw]
Subject: [PATCH] seccomp: fix UAF in user-trap code

On the failure path, we do an fput() of the listener fd if the filter fails
to install (e.g. because of a TSYNC race that's lost, or if the thread is
killed, etc.). fput() doesn't actually release the fd, it just ads it to a
work queue. Then the thread proceeds to free the filter, even though the
listener struct file has a reference to it.

To fix this, on the failure path let's set the private data to null, so we
know in ->release() to ignore the filter.

Reported-by: [email protected]
Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace")
Signed-off-by: Tycho Andersen <[email protected]>
---
This is a little ugly, but I can't really think of a better way (other than
force freeing, but the fput function that does the actual work is declared
static with four underscores :).
---
kernel/seccomp.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index d7f538847b84..e815781ed751 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -976,6 +976,9 @@ static int seccomp_notify_release(struct inode *inode, struct file *file)
struct seccomp_filter *filter = file->private_data;
struct seccomp_knotif *knotif;

+ if (!filter)
+ return 0;
+
mutex_lock(&filter->notify_lock);

/*
@@ -1300,6 +1303,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
out_put_fd:
if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) {
if (ret < 0) {
+ listener_f->private_data = NULL;
fput(listener_f);
put_unused_fd(listener);
} else {
--
2.19.1


2019-01-12 19:26:07

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] seccomp: fix UAF in user-trap code

On Sat, Jan 12, 2019 at 10:24 AM Tycho Andersen <[email protected]> wrote:
>
> On the failure path, we do an fput() of the listener fd if the filter fails
> to install (e.g. because of a TSYNC race that's lost, or if the thread is
> killed, etc.). fput() doesn't actually release the fd, it just ads it to a
> work queue. Then the thread proceeds to free the filter, even though the
> listener struct file has a reference to it.
>
> To fix this, on the failure path let's set the private data to null, so we
> know in ->release() to ignore the filter.
>
> Reported-by: [email protected]
> Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace")
> Signed-off-by: Tycho Andersen <[email protected]>
> ---
> This is a little ugly, but I can't really think of a better way (other than
> force freeing, but the fput function that does the actual work is declared
> static with four underscores :).

This makes sense to me. Thanks for fixing it!

Acked-by: Kees Cook <[email protected]>

James, can you add this to your fixes tree for sending to Linus?

-Kees

> ---
> kernel/seccomp.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/kernel/seccomp.c b/kernel/seccomp.c
> index d7f538847b84..e815781ed751 100644
> --- a/kernel/seccomp.c
> +++ b/kernel/seccomp.c
> @@ -976,6 +976,9 @@ static int seccomp_notify_release(struct inode *inode, struct file *file)
> struct seccomp_filter *filter = file->private_data;
> struct seccomp_knotif *knotif;
>
> + if (!filter)
> + return 0;
> +
> mutex_lock(&filter->notify_lock);
>
> /*
> @@ -1300,6 +1303,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
> out_put_fd:
> if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) {
> if (ret < 0) {
> + listener_f->private_data = NULL;
> fput(listener_f);
> put_unused_fd(listener);
> } else {
> --
> 2.19.1
>


--
Kees Cook

2019-01-16 06:00:17

by James Morris

[permalink] [raw]
Subject: Re: [PATCH] seccomp: fix UAF in user-trap code

On Sat, 12 Jan 2019, Kees Cook wrote:

> This makes sense to me. Thanks for fixing it!
>
> Acked-by: Kees Cook <[email protected]>
>
> James, can you add this to your fixes tree for sending to Linus?

Sure.

--
James Morris
<[email protected]>