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 <[email protected]>
Reported by xingwei lee <[email protected]>
Best Regards,
Yue