[Linux kernel bug] BUG: unable to handle kernel NULL pointer dereference in stack_depot_save_flags

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

 



Dear developers and maintainers,

We encountered a null pointer dereference bug while using our modified
syzkaller. It was tested against the upstream kernel (6.9). The kernel
is compiled by clang-14, kernel config is attached to this email.
Kernel crash log is listed below.
```
BUG: kernel NULL pointer dereference, address: 0000000000000010
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] PREEMPT SMP KASAN NOPTI
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 6.9.0-05151-g1b294a1f3561 #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.13.0-1ubuntu1.1 04/01/2014
RIP: 0010:find_stack lib/stackdepot.c:553 [inline]
RIP: 0010:stack_depot_save_flags+0x1a0/0x850 lib/stackdepot.c:618
Code: 48 89 54 24 18 31 f6 4c 89 44 24 10 e8 69 be c7 ff 31 f6 4c 8b
44 24 10 48 8b 54 24 18 45 85 e4 75 62 4d 8b 3f 49 39 d7 74 5d <45> 39
77 10 75 f2 45 39 47 14 75 ec 31 c0 49 8b 4c c5 00 49 3b 4c
RSP: 0018:ffffc900001e7540 EFLAGS: 00010203
RAX: ffff8880bd200000 RBX: 0000000000000001 RCX: 00000000002086f0
RDX: ffff8880bd4086f0 RSI: 0000000000000000 RDI: 0000000080adfd56
RBP: 0000000000000010 R08: 0000000000000010 R09: ffffc900001e7510
R10: 0000000000000003 R11: ffffffff817b2e00 R12: 1ffff9200003ceb8
R13: ffffc900001e75e0 R14: 00000000fac2086f R15: 0000000000000000
FS:  0000000000000000(0000) GS:ffff8880be400000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000010 CR3: 000000000db34000 CR4: 0000000000750ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
PKRU: 55555554
Call Trace:
 <IRQ>
 save_stack+0xf7/0x1e0 mm/page_owner.c:157
 __set_page_owner+0x89/0x560 mm/page_owner.c:325
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1e6/0x210 mm/page_alloc.c:1534
 prep_new_page mm/page_alloc.c:1541 [inline]
 get_page_from_freelist+0x7d2/0x850 mm/page_alloc.c:3317
 __alloc_pages+0x25e/0x580 mm/page_alloc.c:4575
 __alloc_pages_node include/linux/gfp.h:238 [inline]
 alloc_pages_node include/linux/gfp.h:261 [inline]
 alloc_slab_page+0x6b/0x1a0 mm/slub.c:2190
 allocate_slab+0x5d/0x200 mm/slub.c:2353
 new_slab mm/slub.c:2406 [inline]
 ___slab_alloc+0xa95/0xf20 mm/slub.c:3592
 __slab_alloc mm/slub.c:3682 [inline]
 __slab_alloc_node mm/slub.c:3735 [inline]
 slab_alloc_node mm/slub.c:3908 [inline]
 kmem_cache_alloc_node+0x245/0x390 mm/slub.c:3961
 __alloc_skb+0x19b/0x3f0 net/core/skbuff.c:656
 alloc_skb include/linux/skbuff.h:1308 [inline]
 nlmsg_new include/net/netlink.h:1015 [inline]
 inet6_prefix_notify net/ipv6/addrconf.c:6229 [inline]
 addrconf_prefix_rcv+0x912/0x1660 net/ipv6/addrconf.c:2914
 ndisc_router_discovery+0x17f8/0x38e0 net/ipv6/ndisc.c:1566
 icmpv6_rcv+0x1068/0x18f0 net/ipv6/icmp.c:979
 ip6_protocol_deliver_rcu+0x1064/0x1590 net/ipv6/ip6_input.c:438
 ip6_input_finish+0x17d/0x2c0 net/ipv6/ip6_input.c:483
 NF_HOOK include/linux/netfilter.h:314 [inline]
 ip6_input net/ipv6/ip6_input.c:492 [inline]
 ip6_mc_input+0x9b7/0xc00 net/ipv6/ip6_input.c:586
 ip6_sublist_rcv_finish net/ipv6/ip6_input.c:88 [inline]
 ip6_list_rcv_finish net/ipv6/ip6_input.c:146 [inline]
 ip6_sublist_rcv+0xcb3/0xd20 net/ipv6/ip6_input.c:320
 ipv6_list_rcv+0x431/0x480 net/ipv6/ip6_input.c:355
 __netif_receive_skb_list_ptype net/core/dev.c:5667 [inline]
 __netif_receive_skb_list_core+0x76a/0x9c0 net/core/dev.c:5715
 __netif_receive_skb_list+0x42d/0x4d0 net/core/dev.c:5767
 netif_receive_skb_list_internal+0x5e7/0x910 net/core/dev.c:5859
 gro_normal_list include/net/gro.h:515 [inline]
 napi_complete_done+0x30a/0x800 net/core/dev.c:6202
 e1000_clean+0xf5d/0x3bc0 drivers/net/ethernet/intel/e1000/e1000_main.c:3809
 __napi_poll+0xca/0x480 net/core/dev.c:6721
 napi_poll net/core/dev.c:6790 [inline]
 net_rx_action+0x7cb/0x1000 net/core/dev.c:6906
 handle_softirqs+0x274/0x730 kernel/softirq.c:554
 __do_softirq kernel/softirq.c:588 [inline]
 invoke_softirq kernel/softirq.c:428 [inline]
 __irq_exit_rcu+0xd7/0x1a0 kernel/softirq.c:637
 irq_exit_rcu+0x9/0x20 kernel/softirq.c:649
 common_interrupt+0xaa/0xd0 arch/x86/kernel/irq.c:278
 </IRQ>
 <TASK>
 asm_common_interrupt+0x26/0x40 arch/x86/include/asm/idtentry.h:693
RIP: 0010:native_irq_disable arch/x86/include/asm/irqflags.h:37 [inline]
RIP: 0010:arch_local_irq_disable arch/x86/include/asm/irqflags.h:72 [inline]
RIP: 0010:default_idle+0x13/0x20 arch/x86/kernel/process.c:743
Code: c0 08 00 00 00 4d 29 c8 4c 01 c7 4c 29 c2 e9 76 ff ff ff cc cc
cc cc f3 0f 1e fa 66 90 0f 00 2d 13 07 39 00 f3 0f 1e fa fb f4 <fa> c3
66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa e9 d7 ff ff ff
RSP: 0018:ffffc9000017fdc8 EFLAGS: 000002c6
RAX: 9f03dcce11ef6a00 RBX: ffffffff8166d8ff RCX: 00000000000b05d1
RDX: 0000000000000001 RSI: ffffffff8b6c8be0 RDI: ffffffff8bce04a0
RBP: ffffc9000017ff20 R08: ffff8880be437d0b R09: 1ffff11017c86fa1
R10: dffffc0000000000 R11: ffffed1017c86fa2 R12: 1ffff9200002ffd2
R13: 1ffff1100c15b000 R14: 0000000000000001 R15: dffffc0000000000
 default_idle_call+0x74/0xb0 kernel/sched/idle.c:117
 cpuidle_idle_call kernel/sched/idle.c:191 [inline]
 do_idle+0x20f/0x580 kernel/sched/idle.c:332
 cpu_startup_entry+0x41/0x60 kernel/sched/idle.c:430
 start_secondary+0x100/0x100 arch/x86/kernel/smpboot.c:313
 common_startup_64+0x13e/0x147
 </TASK>
Modules linked in:
CR2: 0000000000000010
---[ end trace 0000000000000000 ]---
RIP: 0010:find_stack lib/stackdepot.c:553 [inline]
RIP: 0010:stack_depot_save_flags+0x1a0/0x850 lib/stackdepot.c:618
Code: 48 89 54 24 18 31 f6 4c 89 44 24 10 e8 69 be c7 ff 31 f6 4c 8b
44 24 10 48 8b 54 24 18 45 85 e4 75 62 4d 8b 3f 49 39 d7 74 5d <45> 39
77 10 75 f2 45 39 47 14 75 ec 31 c0 49 8b 4c c5 00 49 3b 4c
RSP: 0018:ffffc900001e7540 EFLAGS: 00010203
RAX: ffff8880bd200000 RBX: 0000000000000001 RCX: 00000000002086f0
RDX: ffff8880bd4086f0 RSI: 0000000000000000 RDI: 0000000080adfd56
RBP: 0000000000000010 R08: 0000000000000010 R09: ffffc900001e7510
R10: 0000000000000003 R11: ffffffff817b2e00 R12: 1ffff9200003ceb8
R13: ffffc900001e75e0 R14: 00000000fac2086f R15: 0000000000000000
FS:  0000000000000000(0000) GS:ffff8880be400000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000010 CR3: 000000000db34000 CR4: 0000000000750ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
PKRU: 55555554
----------------
Code disassembly (best guess):
   0:    48 89 54 24 18           mov    %rdx,0x18(%rsp)
   5:    31 f6                    xor    %esi,%esi
   7:    4c 89 44 24 10           mov    %r8,0x10(%rsp)
   c:    e8 69 be c7 ff           callq  0xffc7be7a
  11:    31 f6                    xor    %esi,%esi
  13:    4c 8b 44 24 10           mov    0x10(%rsp),%r8
  18:    48 8b 54 24 18           mov    0x18(%rsp),%rdx
  1d:    45 85 e4                 test   %r12d,%r12d
  20:    75 62                    jne    0x84
  22:    4d 8b 3f                 mov    (%r15),%r15
  25:    49 39 d7                 cmp    %rdx,%r15
  28:    74 5d                    je     0x87
* 2a:    45 39 77 10              cmp    %r14d,0x10(%r15) <-- trapping
instruction
  2e:    75 f2                    jne    0x22
  30:    45 39 47 14              cmp    %r8d,0x14(%r15)
  34:    75 ec                    jne    0x22
  36:    31 c0                    xor    %eax,%eax
  38:    49 8b 4c c5 00           mov    0x0(%r13,%rax,8),%rcx
  3d:    49                       rex.WB
  3e:    3b                       .byte 0x3b
  3f:    4c                       rex.WR
```

The syz repro shows that it only consist of open to /dev/sg and an
ioctl to that device: (For how to execute syz repro, please refer to
introduction of syzkaller:
https://github.com/google/syzkaller/blob/master/docs/executing_syzkaller_programs.md)

```
r0 = syz_open_dev$sg(&(0x7f0000004f00), 0x0, 0x0)
ioctl$SCSI_IOCTL_SEND_COMMAND(r0, 0x1,
&(0x7f0000000040)=ANY=[@ANYBLOB="0000000007000000850a455584e48b565869e5b0ce4925"])
```

The C repro is listed below:

```
#define _GNU_SOURCE

#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static void sleep_ms(uint64_t ms)
{
  usleep(ms * 1000);
}

static uint64_t current_time_ms(void)
{
  struct timespec ts;
  if (clock_gettime(CLOCK_MONOTONIC, &ts))
    exit(1);
  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}

static bool write_file(const char* file, const char* what, ...)
{
  char buf[1024];
  va_list args;
  va_start(args, what);
  vsnprintf(buf, sizeof(buf), what, args);
  va_end(args);
  buf[sizeof(buf) - 1] = 0;
  int len = strlen(buf);
  int fd = open(file, O_WRONLY | O_CLOEXEC);
  if (fd == -1)
    return false;
  if (write(fd, buf, len) != len) {
    int err = errno;
    close(fd);
    errno = err;
    return false;
  }
  close(fd);
  return true;
}

static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
{
  if (a0 == 0xc || a0 == 0xb) {
    char buf[128];
    sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
            (uint8_t)a2);
    return open(buf, O_RDWR, 0);
  } else {
    char buf[1024];
    char* hash;
    strncpy(buf, (char*)a0, sizeof(buf) - 1);
    buf[sizeof(buf) - 1] = 0;
    while ((hash = strchr(buf, '#'))) {
      *hash = '0' + (char)(a1 % 10);
      a1 /= 10;
    }
    return open(buf, a2, 0);
  }
}

static void kill_and_wait(int pid, int* status)
{
  kill(-pid, SIGKILL);
  kill(pid, SIGKILL);
  for (int i = 0; i < 100; i++) {
    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
      return;
    usleep(1000);
  }
  DIR* dir = opendir("/sys/fs/fuse/connections");
  if (dir) {
    for (;;) {
      struct dirent* ent = readdir(dir);
      if (!ent)
        break;
      if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
        continue;
      char abort[300];
      snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
               ent->d_name);
      int fd = open(abort, O_WRONLY);
      if (fd == -1) {
        continue;
      }
      if (write(fd, abort, 1) < 0) {
      }
      close(fd);
    }
    closedir(dir);
  } else {
  }
  while (waitpid(-1, status, __WALL) != pid) {
  }
}

static void setup_test()
{
  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
  setpgrp();
  write_file("/proc/self/oom_score_adj", "1000");
}

static void setup_sysctl()
{
  char mypid[32];
  snprintf(mypid, sizeof(mypid), "%d", getpid());
  struct {
    const char* name;
    const char* data;
  } files[] = {
      {"/sys/kernel/debug/x86/nmi_longest_ns", "10000000000"},
      {"/proc/sys/kernel/hung_task_check_interval_secs", "20"},
      {"/proc/sys/net/core/bpf_jit_kallsyms", "1"},
      {"/proc/sys/net/core/bpf_jit_harden", "0"},
      {"/proc/sys/kernel/kptr_restrict", "0"},
      {"/proc/sys/kernel/softlockup_all_cpu_backtrace", "1"},
      {"/proc/sys/fs/mount-max", "100"},
      {"/proc/sys/vm/oom_dump_tasks", "0"},
      {"/proc/sys/debug/exception-trace", "0"},
      {"/proc/sys/kernel/printk", "7 4 1 3"},
      {"/proc/sys/kernel/keys/gc_delay", "1"},
      {"/proc/sys/vm/oom_kill_allocating_task", "1"},
      {"/proc/sys/kernel/ctrl-alt-del", "0"},
      {"/proc/sys/kernel/cad_pid", mypid},
  };
  for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) {
    if (!write_file(files[i].name, files[i].data))
      printf("write to %s failed: %s\n", files[i].name, strerror(errno));
  }
}

static void execute_one(void);

#define WAIT_FLAGS __WALL

static void loop(void)
{
  int iter = 0;
  for (;; iter++) {
    int pid = fork();
    if (pid < 0)
      exit(1);
    if (pid == 0) {
      setup_test();
      execute_one();
      exit(0);
    }
    int status = 0;
    uint64_t start = current_time_ms();
    for (;;) {
      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
        break;
      sleep_ms(1);
      if (current_time_ms() - start < 5000)
        continue;
      kill_and_wait(pid, &status);
      break;
    }
  }
}

uint64_t r[1] = {0xffffffffffffffff};

void execute_one(void)
{
  intptr_t res = 0;
  memcpy((void*)0x20004f00, "/dev/sg#\000", 9);
  res = -1;
  res = syz_open_dev(/*dev=*/0x20004f00, /*id=*/0, /*flags=*/0);
  if (res != -1)
    r[0] = res;
  memcpy((void*)0x20000040,
         "\x00\x00\x00\x00\x07\x00\x00\x00\x85\x0a\x45\x55\x84\xe4\x8b\x56\x58"
         "\x69\xe5\xb0\xce\x49\x25",
         23);
  syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/1, /*arg=*/0x20000040ul);
}
int main(void)
{
  syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul,
          /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  setup_sysctl();
  loop();
  return 0;
}
```

We tested this C repro on the latest commit of the upstream kernel. It
still crashed but at a different location. Here is another bug that
crashes elsewhere but may have the same root cause:

```
BUG: Bad rss-counter state mm:ffff8880668dc280 type:MM_ANONPAGES val:2
BUG: non-zero pgtables_bytes on freeing mm: 4096
------------[ cut here ]------------
WARNING: CPU: 1 PID: 8096 at include/linux/mmap_lock.h:71
mmap_assert_write_locked include/linux/mmap_lock.h:71 [inline]
WARNING: CPU: 1 PID: 8096 at include/linux/mmap_lock.h:71
__is_vma_write_locked include/linux/mm.h:708 [inline]
WARNING: CPU: 1 PID: 8096 at include/linux/mmap_lock.h:71
vma_start_write include/linux/mm.h:727 [inline]
WARNING: CPU: 1 PID: 8096 at include/linux/mmap_lock.h:71
dup_mmap+0xf44/0x1a30 kernel/fork.c:671
Modules linked in:
CPU: 1 PID: 8096 Comm: syz-executor375 Not tainted 6.9.0-05151-g1b294a1f3561 #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.13.0-1ubuntu1.1 04/01/2014
RIP: 0010:mmap_assert_write_locked include/linux/mmap_lock.h:71 [inline]
RIP: 0010:__is_vma_write_locked include/linux/mm.h:708 [inline]
RIP: 0010:vma_start_write include/linux/mm.h:727 [inline]
RIP: 0010:dup_mmap+0xf44/0x1a30 kernel/fork.c:671
Code: 89 f7 48 c7 c6 ff ff ff ff e8 e8 9d cf 09 48 85 c0 0f 84 e0 00
00 00 48 89 c3 e8 27 76 3b 00 e9 d5 f7 ff ff e8 1d 76 3b 00 90 <0f> 0b
90 e9 3d f8 ff ff 48 c7 c1 6c 98 4b 8f 80 e1 07 80 c1 03 38
RSP: 0018:ffffc90002a8f8c0 EFLAGS: 00010293
RAX: ffffffff815305b3 RBX: 0000000000000000 RCX: ffff88801b580000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffffc90002a8fa28 R08: ffffffff8152fde5 R09: ffffffff8b227880
R10: 0000000000000004 R11: ffff88801b580000 R12: ffff88806bf89c10
R13: 1ffff1100d7f1382 R14: 0000000000000000 R15: dffffc0000000000
FS:  000055558d7ad880(0000) GS:ffff8880be400000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020000048 CR3: 0000000068130000 CR4: 0000000000750ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
PKRU: 55555554
Call Trace:
 <TASK>
 dup_mm kernel/fork.c:1688 [inline]
 copy_mm+0x143/0x430 kernel/fork.c:1737
 copy_process+0x1810/0x3d30 kernel/fork.c:2390
 kernel_clone+0x228/0x6b0 kernel/fork.c:2797
 __do_sys_clone kernel/fork.c:2940 [inline]
 __se_sys_clone kernel/fork.c:2924 [inline]
 __x64_sys_clone+0x26b/0x2e0 kernel/fork.c:2924
 do_syscall_x64 arch/x86/entry/common.c:52 [inline]
 do_syscall_64+0xe4/0x240 arch/x86/entry/common.c:83
 entry_SYSCALL_64_after_hwframe+0x67/0x6f
RIP: 0033:0x7f5a28557e7f
Code: ed 0f 85 64 01 00 00 64 4c 8b 0c 25 10 00 00 00 45 31 c0 4d 8d
91 d0 02 00 00 31 d2 31 f6 bf 11 00 20 01 b8 38 00 00 00 0f 05 <48> 3d
00 f0 ff ff 0f 87 f5 00 00 00 41 89 c5 85 c0 0f 85 fc 00 00
RSP: 002b:00007ffd62c1f6c0 EFLAGS: 00000246 ORIG_RAX: 0000000000000038
RAX: ffffffffffffffda RBX: 0000000000001fa4 RCX: 00007f5a28557e7f
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000001200011
RBP: 0000000000000000 R08: 0000000000000000 R09: 000055558d7ad880
R10: 000055558d7adb50 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffd62c1f700 R14: 0000000000000002 R15: 00007ffd62c1f720
 </TASK>
```
The C repro is listed below:
```
// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static void sleep_ms(uint64_t ms)
{
  usleep(ms * 1000);
}

static uint64_t current_time_ms(void)
{
  struct timespec ts;
  if (clock_gettime(CLOCK_MONOTONIC, &ts))
    exit(1);
  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}

static void use_temporary_dir(void)
{
  char tmpdir_template[] = "./syzkaller.XXXXXX";
  char* tmpdir = mkdtemp(tmpdir_template);
  if (!tmpdir)
    exit(1);
  if (chmod(tmpdir, 0777))
    exit(1);
  if (chdir(tmpdir))
    exit(1);
}

static bool write_file(const char* file, const char* what, ...)
{
  char buf[1024];
  va_list args;
  va_start(args, what);
  vsnprintf(buf, sizeof(buf), what, args);
  va_end(args);
  buf[sizeof(buf) - 1] = 0;
  int len = strlen(buf);
  int fd = open(file, O_WRONLY | O_CLOEXEC);
  if (fd == -1)
    return false;
  if (write(fd, buf, len) != len) {
    int err = errno;
    close(fd);
    errno = err;
    return false;
  }
  close(fd);
  return true;
}

static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
{
  if (a0 == 0xc || a0 == 0xb) {
    char buf[128];
    sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1,
            (uint8_t)a2);
    return open(buf, O_RDWR, 0);
  } else {
    char buf[1024];
    char* hash;
    strncpy(buf, (char*)a0, sizeof(buf) - 1);
    buf[sizeof(buf) - 1] = 0;
    while ((hash = strchr(buf, '#'))) {
      *hash = '0' + (char)(a1 % 10);
      a1 /= 10;
    }
    return open(buf, a2, 0);
  }
}

#define FS_IOC_SETFLAGS _IOW('f', 2, long)
static void remove_dir(const char* dir)
{
  int iter = 0;
  DIR* dp = 0;
retry:
  while (umount2(dir, MNT_DETACH | UMOUNT_NOFOLLOW) == 0) {
  }
  dp = opendir(dir);
  if (dp == NULL) {
    if (errno == EMFILE) {
      exit(1);
    }
    exit(1);
  }
  struct dirent* ep = 0;
  while ((ep = readdir(dp))) {
    if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
      continue;
    char filename[FILENAME_MAX];
    snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
    while (umount2(filename, MNT_DETACH | UMOUNT_NOFOLLOW) == 0) {
    }
    struct stat st;
    if (lstat(filename, &st))
      exit(1);
    if (S_ISDIR(st.st_mode)) {
      remove_dir(filename);
      continue;
    }
    int i;
    for (i = 0;; i++) {
      if (unlink(filename) == 0)
        break;
      if (errno == EPERM) {
        int fd = open(filename, O_RDONLY);
        if (fd != -1) {
          long flags = 0;
          if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
          }
          close(fd);
          continue;
        }
      }
      if (errno == EROFS) {
        break;
      }
      if (errno != EBUSY || i > 100)
        exit(1);
      if (umount2(filename, MNT_DETACH | UMOUNT_NOFOLLOW))
        exit(1);
    }
  }
  closedir(dp);
  for (int i = 0;; i++) {
    if (rmdir(dir) == 0)
      break;
    if (i < 100) {
      if (errno == EPERM) {
        int fd = open(dir, O_RDONLY);
        if (fd != -1) {
          long flags = 0;
          if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
          }
          close(fd);
          continue;
        }
      }
      if (errno == EROFS) {
        break;
      }
      if (errno == EBUSY) {
        if (umount2(dir, MNT_DETACH | UMOUNT_NOFOLLOW))
          exit(1);
        continue;
      }
      if (errno == ENOTEMPTY) {
        if (iter < 100) {
          iter++;
          goto retry;
        }
      }
    }
    exit(1);
  }
}

static void kill_and_wait(int pid, int* status)
{
  kill(-pid, SIGKILL);
  kill(pid, SIGKILL);
  for (int i = 0; i < 100; i++) {
    if (waitpid(-1, status, WNOHANG | __WALL) == pid)
      return;
    usleep(1000);
  }
  DIR* dir = opendir("/sys/fs/fuse/connections");
  if (dir) {
    for (;;) {
      struct dirent* ent = readdir(dir);
      if (!ent)
        break;
      if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
        continue;
      char abort[300];
      snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
               ent->d_name);
      int fd = open(abort, O_WRONLY);
      if (fd == -1) {
        continue;
      }
      if (write(fd, abort, 1) < 0) {
      }
      close(fd);
    }
    closedir(dir);
  } else {
  }
  while (waitpid(-1, status, __WALL) != pid) {
  }
}

static void setup_test()
{
  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
  setpgrp();
  write_file("/proc/self/oom_score_adj", "1000");
  if (symlink("/dev/binderfs", "./binderfs")) {
  }
}

static void execute_one(void);

#define WAIT_FLAGS __WALL

static void loop(void)
{
  int iter = 0;
  for (;; iter++) {
    char cwdbuf[32];
    sprintf(cwdbuf, "./%d", iter);
    if (mkdir(cwdbuf, 0777))
      exit(1);
    int pid = fork();
    if (pid < 0)
      exit(1);
    if (pid == 0) {
      if (chdir(cwdbuf))
        exit(1);
      setup_test();
      execute_one();
      exit(0);
    }
    int status = 0;
    uint64_t start = current_time_ms();
    for (;;) {
      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
        break;
      sleep_ms(1);
      if (current_time_ms() - start < 5000)
        continue;
      kill_and_wait(pid, &status);
      break;
    }
    remove_dir(cwdbuf);
  }
}

uint64_t r[1] = {0xffffffffffffffff};

void execute_one(void)
{
  intptr_t res = 0;
  syscall(__NR_ioctl, /*fd=*/-1, /*cmd=*/0xc0c0583b, /*arg=*/0ul);
  memcpy((void*)0x20004f00, "/dev/sg#\000", 9);
  res = -1;
  res = syz_open_dev(/*dev=*/0x20004f00, /*id=*/0, /*flags=*/0);
  if (res != -1)
    r[0] = res;
  memcpy((void*)0x20000040,
         "\x00\x00\x00\x00\x07\x00\x00\x00\x85\x0a\x45\x55\x84\xe4\x8b\x56\x58"
         "\x69\xe5\xb0\xce\x49\x25",
         23);
  syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/1, /*arg=*/0x20000040ul);
}
int main(void)
{
  syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul,
          /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  use_temporary_dir();
  loop();
  return 0;
}
```

If you have any questions, please contact us.

Reported by Yue Sun <samsun1006219@xxxxxxxxx>
Reported by xingwei lee <xrivendell7@xxxxxxxxx>

Best Regards,
Yue

Attachment: config
Description: Binary data


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux