Re: general protection fault in show_timer

From: Alexey Dobriyan
Date: Thu Nov 30 2017 - 07:20:33 EST


[cc security@]
100% oops with interrupts disabled by nobody
or kernel memory read


On 11/30/17, Dmitry Vyukov <dvyukov@xxxxxxxxxx> wrote:
> On Thu, Nov 30, 2017 at 12:31 PM, Dmitry Vyukov <dvyukov@xxxxxxxxxx> wrote:
>> On Thu, Nov 30, 2017 at 12:08 PM, Alexey Dobriyan <adobriyan@xxxxxxxxx>
>> wrote:
>>> On 11/30/17, syzbot
>>> <bot+054c6cd125793643a90db21e4b9ddc71a881f797@xxxxxxxxxxxxxxxxxxxxxxxxx>
>>> wrote:
>>>> Hello,
>>>>
>>>> syzkaller hit the following crash on
>>>> 43570f0383d6d5879ae585e6c3cf027ba321546f
>>>> git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/master
>>>> compiler: gcc (GCC) 7.1.1 20170620
>>>> .config is attached
>>>> Raw console output is attached.
>>>>
>>>> Unfortunately, I don't have any reproducer for this bug yet.
>>>>
>>>>
>>>> kasan: CONFIG_KASAN_INLINE enabled
>>>> kasan: GPF could be caused by NULL-ptr deref or user memory access
>>>> general protection fault: 0000 [#1] SMP KASAN
>>>> Dumping ftrace buffer:
>>>> (ftrace buffer empty)
>>>> Modules linked in:
>>>> CPU: 1 PID: 22618 Comm: syz-executor4 Not tainted 4.15.0-rc1+ #199
>>>> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
>>>> Google 01/01/2011
>>>> task: ffff8801c048c400 task.stack: ffff8801cd968000
>>>> RIP: 0010:show_timer+0x1c7/0x2b0 fs/proc/base.c:2274
>>>> RSP: 0018:ffff8801cd96f9e0 EFLAGS: 00010006
>>>> RAX: dffffc0000000000 RBX: ffff8801cff22e40 RCX: ffffffff81ccb88e
>>>> RDX: 0000000030a68524 RSI: ffffc90002dea000 RDI: 0000000185342920
>>>> RBP: ffff8801cd96fa10 R08: ffffed003a0514c5 R09: ffffed003a0514c5
>>>> R10: ffff8801c048c400 R11: ffffed003a0514c4 R12: 0000000040000000
>>>> R13: ffff8801c79e7000 R14: ffffffff853419e0 R15: 0000000000000507
>>>> FS: 00007f19f811e700(0000) GS:ffff8801db500000(0000)
>>>> knlGS:0000000000000000
>>>> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>>> CR2: 00007f4ab586bdb8 CR3: 00000001d1788000 CR4: 00000000001426e0
>>>> DR0: 0000000020000000 DR1: 0000000020000008 DR2: 0000000000000000
>>>> DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000600
>>>> Call Trace:
>>>> traverse+0x248/0xa00 fs/seq_file.c:111
>>>> seq_read+0x96a/0x13d0 fs/seq_file.c:189
>>>> do_loop_readv_writev fs/read_write.c:673 [inline]
>>>> do_iter_read+0x3db/0x5b0 fs/read_write.c:897
>>>> vfs_readv+0x121/0x1c0 fs/read_write.c:959
>>>> do_preadv+0x11b/0x1a0 fs/read_write.c:1043
>>>> SYSC_preadv fs/read_write.c:1093 [inline]
>>>> SyS_preadv+0x30/0x40 fs/read_write.c:1088
>>>> entry_SYSCALL_64_fastpath+0x1f/0x96
>>>> RIP: 0033:0x4529d9
>>>> RSP: 002b:00007f19f811dc58 EFLAGS: 00000212 ORIG_RAX: 0000000000000127
>>>> RAX: ffffffffffffffda RBX: 00007f19f811d950 RCX: 00000000004529d9
>>>> RDX: 0000000000000001 RSI: 00000000205e2ff0 RDI: 0000000000000013
>>>> RBP: 00007f19f811d940 R08: 0000000000000000 R09: 0000000000000000
>>>> R10: 0001000000000000 R11: 0000000000000212 R12: 00000000004b7346
>>>> R13: 00007f19f811dac8 R14: 00000000004b7351 R15: 0000000000000000
>>>> Code: 89 c7 4c 0f 44 f1 41 83 e4 fb 4d 63 e4 e8 a2 2f a3 ff 4a 8d 3c e5
>>>> 20
>>>>
>>>> 29 34 85 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02
>>>> 00
>>>> 0f 85 a2 00 00 00 4a 8b 14 e5 20 29 34 85 4c 89 ef
>>>> RIP: show_timer+0x1c7/0x2b0 fs/proc/base.c:2274 RSP: ffff8801cd96f9e0
>>>
>>> This looks like ASAN problem
>>>
>>> ffffffff81a5f1d9: e8 72 74 b7 ff call
>>> ffffffff815d6650 <__sanitizer_cov_trace_pc>
>>> ffffffff81a5f1de: 4a 8d 3c e5 a0 9e b4 lea
>>> rdi,[r12*8-0x7b4b6160]
>>> ffffffff81a5f1e5: 84
>>> ffffffff81a5f1e6: 48 b8 00 00 00 00 00 movabs
>>> rax,0xdffffc0000000000
>>> ffffffff81a5f1ed: fc ff df
>>> ffffffff81a5f1f0: 48 89 fa mov rdx,rdi
>>> ffffffff81a5f1f3: 48 c1 ea 03 shr rdx,0x3
>>> ffffffff81a5f1f7: 80 3c 02 00 ===>cmp BYTE PTR
>>> [rdx+rax*1],0x0 <====
>>>
>>> This is code injected by KASAN_INLINE
>>>
>>> timer_show() looks seemingly fine:
>>> "timer" pointer is valid otherwise code would oopsed earlier
>>> tp->ns is valid otherwise it'd oopsed inside pid_nr_ns()
>>
>>
>> This is not KASAN bug. Kernel tries to dereference 0x0000000185342920.
>> Failure mode is just different.

I'm new to KASAN.

> it seems that notify is equal to 0x0000000040000000 and this makes
> nstr[notify & ~SIGEV_THREAD_ID] a totally wild access.

[nods]
you named the bug already

"notify" directly comes from userspace struct sigevent::sigev_notify
without adult supervision.

Reproducer is timer_create + read(/proc/self/timers)

BUG: unable to handle kernel paging request at 00000000b3695f68
IP: show_timer+0x73/0xa0
PGD 3d18f067 P4D 3d18f067 PUD 0
Oops: 0000 [#1] PREEMPT SMP
CPU: 0 PID: 2819 Comm: a.out Not tainted 4.15.0-rc1-00179-ga0908a1b7d68 #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.10.2-1.fc27 04/01/2014
task: 00000000ea51a5c5 task.stack: 00000000d68c2dbc
RIP: 0010:show_timer+0x73/0xa0
RSP: 0018:ffffc900001bfdd0 EFLAGS: 00010006
RAX: ffffffff814cddbd RBX: 0000000040000000 RCX: ffffffff814cddbd
RDX: 0000000000000000 RSI: ffffffff814d9419 RDI: ffff88003dab9500
RBP: ffff88003dab9500 R08: 0000000000000b03 R09: 0000000000000007
R10: ffffc9000040b908 R11: ffff88003d9ce020 R12: ffff88003c1c6570
R13: ffff88003d514d80 R14: ffff88003dab9500 R15: ffff88003c1c6570
FS: 00007f52624f0700(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000181414880 CR3: 000000003c243000 CR4: 00000000000006b0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
seq_read+0xe6/0x3b0
__vfs_read+0x1e/0x120
? ptrace_do_notify+0x6a/0x80
vfs_read+0x84/0x110
SyS_read+0x3d/0xa0
do_syscall_64+0x4b/0x180
entry_SYSCALL64_slow_path+0x25/0x25
RIP: 0033:0x7f5261e15fc0
RSP: 002b:00007ffd2f89f5c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f5261e15fc0
RDX: 0000000000001000 RSI: 00007ffd2f89f620 RDI: 0000000000000003
RBP: 0000000000000000 R08: 00007f52620cce40 R09: 00007f5261d47c60
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000400574
R13: 00007ffd2f8a0700 R14: 0000000000000000 R15: 0000000000000000
Code: 89 f1 ff f6 c3 04 48 89 ef 48 c7 c1 c9 44 4c 81 41 89 c0 48 c7
c0 bd dd 4c 81 48 c7 c6 19 94 4d 81 48 0f 44 c8 83 e3 fb 48 63 db <48>
8b 14 dd 80 48 41 81 e8 f0 3b fd ff 41 8b 54 24 30 48 89 ef
RIP: show_timer+0x73/0xa0 RSP: ffffc900001bfdd0
CR2: 0000000181414880
---[ end trace 99049f704e3a24ad ]---
note: a.out[2819] exited with preempt_count 1
#include <string.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
struct sigevent sev;
timer_t id;
char buf[4096];
int fd;

memset(&sev, 0, sizeof(struct sigevent));
sev.sigev_value.sival_int = SIGEV_SIGNAL;
sev.sigev_value.sival_ptr = (void *)1UL;
sev.sigev_signo = 1;
sev.sigev_notify = 0x40000000;

memset(&id, 0, sizeof(timer_t));

timer_create(CLOCK_MONOTONIC, &sev, &id);
fd = open("/proc/self/timers", O_RDONLY);
read(fd, buf, sizeof(buf));

return 0;
}