Re: BUG: null pointer dereference in seccomp

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 29, 2024 at 2:38 AM Kees Cook <kees@xxxxxxxxxx> wrote:
> On Tue, Aug 27, 2024 at 09:09:49PM -0700, Juefei Pu wrote:
> > Hello,
> > We found the following null-pointer-dereference issue using syzkaller
> > on Linux v6.10.
>
> In seccomp! Yikes.
>
> > Unfortunately, the syzkaller failed to generate a reproducer.
>
> That's a bummer.
>
> > But at least we have the report:
> >
> > Oops: general protection fault, probably for non-canonical address
> > 0xdffffc0000000006: 0000 [#1] PREEMPT SMP KASAN PTI
> > KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037]
> > CPU: 0 PID: 4493 Comm: systemd-journal Not tainted 6.10.0 #13
> > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
> > RIP: 0010:__bpf_prog_run include/linux/filter.h:691 [inline]
>
> This doesn't look like a NULL deref, this looks like a corrupted
> pointer: 0xdffffc0000000006.

No, it really is a NULL deref - in a non-KASAN build, you'd see a page
fault at virtual address 0x30. KASAN builds with inline
instrumentation cause a GPF on NULL deref because they try to first
check the KASAN shadow mapping for that address, and applying the
shadow address calculation to NULL (or addresses in the low address
space half) gives non-canonical addresses.

This line directly below the oops message is supposed to point this
out (it works by decoding the faulting instruction, calculating the
effective address of the access, and then having KASAN calculate
backwards from the shadow address what the original address could have
been):

KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037]

> Is prog bad or dfunc bad? I assume the
> former, as dfunc is hard-coded below...
>
>                 ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
>
> > RIP: 0010:bpf_prog_run include/linux/filter.h:698 [inline]
>
>         return __bpf_prog_run(prog, ctx, bpf_dispatcher_nop_func);
>
> > RIP: 0010:bpf_prog_run_pin_on_cpu include/linux/filter.h:715 [inline]
>
>         ret = bpf_prog_run(prog, ctx);
>
> > RIP: 0010:seccomp_run_filters+0x17a/0x3f0 kernel/seccomp.c:426
>
>                 u32 cur_ret = bpf_prog_run_pin_on_cpu(f->prog, sd);
>
> > Code: 00 00 e8 99 36 d2 ff 0f 1f 44 00 00 e8 cf 58 ff ff 48 8d 5d 48
> > 48 83 c5 30 48 89 e8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c
> > 08 00 74 08 48 89 ef e8 c8 63 62 00 4c 8b 5d 00 48 8b 3c 24
> > RSP: 0018:ffffc90002cb7be0 EFLAGS: 00010206
> > RAX: 0000000000000006 RBX: 0000000000000048 RCX: dffffc0000000000
> > RDX: 0000000000000000 RSI: 00000000000002a4 RDI: ffffffff8b517360
> > RBP: 0000000000000030 R08: ffffffff8191f8eb R09: 1ffff11004039e86
> > R10: dffffc0000000000 R11: ffffffffa00016d0 R12: 000000007fff0000
> > R13: ffff88801f84a800 R14: ffffc90002cb7df0 R15: 000000007fff0000
> > FS:  00007f897e849900(0000) GS:ffff888063a00000(0000) knlGS:0000000000000000
> > CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > CR2: 00007f897d771b08 CR3: 00000000195fe000 CR4: 0000000000350ef0
> > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> > Call Trace:
> >  <TASK>
> >  __seccomp_filter+0x46f/0x1c70 kernel/seccomp.c:1222
> >  syscall_trace_enter+0xa4/0x140 kernel/entry/common.c:52
> >  syscall_enter_from_user_mode_work include/linux/entry-common.h:168 [inline]
> >  syscall_enter_from_user_mode include/linux/entry-common.h:198 [inline]
> >  do_syscall_64+0x5d/0x150 arch/x86/entry/common.c:79
> >  entry_SYSCALL_64_after_hwframe+0x67/0x6f
>
> Has anything changed in BPF in this area lately?
>
> > RIP: 0033:0x7f897ed171e4
> > Code: 84 00 00 00 00 00 44 89 54 24 0c e8 36 58 f9 ff 44 8b 54 24 0c
> > 44 89 e2 48 89 ee 41 89 c0 bf 9c ff ff ff b8 01 01 00 00 0f 05 <48> 3d
> > 00 f0 ff ff 77 34 44 89 c7 89 44 24 0c e8 68 58 f9 ff 8b 44
> > RSP: 002b:00007ffd4ae74a60 EFLAGS: 00000293 ORIG_RAX: 0000000000000101
> > RAX: ffffffffffffffda RBX: 00005627cd785ed0 RCX: 00007f897ed171e4
> > RDX: 0000000000290000 RSI: 00007f897f010d0a RDI: 00000000ffffff9c
> > RBP: 00007f897f010d0a R08: 0000000000000000 R09: 0034353132303865
> > R10: 0000000000000000 R11: 0000000000000293 R12: 0000000000290000
> > R13: 00007ffd4ae74d20 R14: 0000000000000000 R15: 00007ffd4ae74e28
> >  </TASK>
> > Modules linked in:
> > ---[ end trace 0000000000000000 ]---
> > RIP: 0010:__bpf_prog_run include/linux/filter.h:691 [inline]
> > RIP: 0010:bpf_prog_run include/linux/filter.h:698 [inline]
> > RIP: 0010:bpf_prog_run_pin_on_cpu include/linux/filter.h:715 [inline]
> > RIP: 0010:seccomp_run_filters+0x17a/0x3f0 kernel/seccomp.c:426
> > Code: 00 00 e8 99 36 d2 ff 0f 1f 44 00 00 e8 cf 58 ff ff 48 8d 5d 48
> > 48 83 c5 30 48 89 e8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c
> > 08 00 74 08 48 89 ef e8 c8 63 62 00 4c 8b 5d 00 48 8b 3c 24
> > RSP: 0018:ffffc90002cb7be0 EFLAGS: 00010206
> > RAX: 0000000000000006 RBX: 0000000000000048 RCX: dffffc0000000000
> > RDX: 0000000000000000 RSI: 00000000000002a4 RDI: ffffffff8b517360
> > RBP: 0000000000000030 R08: ffffffff8191f8eb R09: 1ffff11004039e86
> > R10: dffffc0000000000 R11: ffffffffa00016d0 R12: 000000007fff0000
> > R13: ffff88801f84a800 R14: ffffc90002cb7df0 R15: 000000007fff0000
> > FS:  00007f897e849900(0000) GS:ffff888063a00000(0000) knlGS:0000000000000000
> > CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > CR2: 00007f521f8ca000 CR3: 00000000195fe000 CR4: 0000000000350ef0
> > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> > ----------------
> > Code disassembly (best guess):
> >    0: 00 00                 add    %al,(%rax)
> >    2: e8 99 36 d2 ff       call   0xffd236a0
> >    7: 0f 1f 44 00 00       nopl   0x0(%rax,%rax,1)
> >    c: e8 cf 58 ff ff       call   0xffff58e0
> >   11: 48 8d 5d 48           lea    0x48(%rbp),%rbx

This LEA looks like it's calculating the address of prog->insnsi.

> >   15: 48 83 c5 30           add    $0x30,%rbp
> >   19: 48 89 e8             mov    %rbp,%rax
> >   1c: 48 c1 e8 03           shr    $0x3,%rax
> >   20: 48 b9 00 00 00 00 00 movabs $0xdffffc0000000000,%rcx
> >   27: fc ff df
> > * 2a: 80 3c 08 00           cmpb   $0x0,(%rax,%rcx,1) <-- trapping instruction

Here you can see - the access happens at rax+rcx, which is
(rbp>>3)+0xdffffc0000000000. rbp is the actual pointer that will be
accessed; this shift-right-and-add-0xdffffc0000000000 pattern is how
inline KASAN instrumentation determines the shadow address.

> >   2e: 74 08                 je     0x38

Normally we jump over the next two instructions, if the KASAN shadow
is 0 (which means fully accessible)...

> >   30: 48 89 ef             mov    %rbp,%rdi
> >   33: e8 c8 63 62 00       call   0x626400

... continue here:

> >   38: 4c 8b 5d 00           mov    0x0(%rbp),%r11

And here's the actual access to rbp, which is probably loading the
prog->bpf_func.

> >   3c: 48 8b 3c 24           mov    (%rsp),%rdi
>
> What's the movabs? I don't have anything like that in my vmlinux binary
> output. Is this KASAN perhaps?

Yes, inline KASAN.


>
> Regardless, I don't see how prog could be NULL. :( It shouldn't be
> possible without some kind of major refcounting bug.





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux