Created
April 18, 2023 03:40
-
-
Save ZHYfeng/eb410de5d7aec253d8c83cf34e628d6a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Syzkaller hit 'BUG: sleeping function called from invalid context in __might_resched' bug. | |
BUG: sleeping function called from invalid context at kernel/printk/printk.c:2656 | |
in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 9817, name: (agetty) | |
preempt_count: 1, expected: 0 | |
RCU nest depth: 0, expected: 0 | |
3 locks held by (agetty)/9817: | |
#0: ffff888017797098 (&tty->ldisc_sem){++++}-{0:0}, at: tty_ldisc_ref_wait+0x27/0x80 drivers/tty/tty_ldisc.c:244 | |
#1: ffff888017797130 (&tty->atomic_write_lock){+.+.}-{3:3}, at: tty_write_lock+0x23/0x90 drivers/tty/tty_io.c:944 | |
#2: ffff888046ee93e0 (&gsm->tx_lock){....}-{2:2}, at: gsmld_write+0x63/0x150 drivers/tty/n_gsm.c:3410 | |
irq event stamp: 3146 | |
hardirqs last enabled at (3145): [<ffffffff8a0f3a32>] syscall_enter_from_user_mode+0x22/0xb0 kernel/entry/common.c:111 | |
hardirqs last disabled at (3146): [<ffffffff8a12e6b3>] __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:108 [inline] | |
hardirqs last disabled at (3146): [<ffffffff8a12e6b3>] _raw_spin_lock_irqsave+0x53/0x60 kernel/locking/spinlock.c:162 | |
softirqs last enabled at (0): [<ffffffff814b301d>] copy_process+0x1a8d/0x7490 kernel/fork.c:2211 | |
softirqs last disabled at (0): [<0000000000000000>] 0x0 | |
Preemption disabled at: | |
[<0000000000000000>] 0x0 | |
CPU: 0 PID: 9817 Comm: (agetty) Not tainted 6.2.0 #1 | |
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 | |
Call Trace: | |
<TASK> | |
__dump_stack lib/dump_stack.c:88 [inline] | |
dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 | |
__might_resched.cold+0x222/0x26b kernel/sched/core.c:10045 | |
console_lock+0x1c/0x80 kernel/printk/printk.c:2656 | |
do_con_write+0x114/0x1e40 drivers/tty/vt/vt.c:2908 | |
con_write+0x26/0x40 drivers/tty/vt/vt.c:3295 | |
gsmld_write+0xd0/0x150 drivers/tty/n_gsm.c:3413 | |
do_tty_write drivers/tty/tty_io.c:1018 [inline] | |
file_tty_write.isra.0+0x48f/0x820 drivers/tty/tty_io.c:1089 | |
call_write_iter include/linux/fs.h:2189 [inline] | |
new_sync_write fs/read_write.c:491 [inline] | |
vfs_write+0x9cf/0xd90 fs/read_write.c:584 | |
ksys_write+0x12c/0x250 fs/read_write.c:637 | |
do_syscall_x64 arch/x86/entry/common.c:50 [inline] | |
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 | |
entry_SYSCALL_64_after_hwframe+0x63/0xcd | |
RIP: 0033:0x7f5538c101b0 | |
Code: 2e 0f 1f 84 00 00 00 00 00 90 48 8b 05 19 7e 20 00 c3 0f 1f 84 00 00 00 00 00 83 3d 19 c2 20 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 ae fc ff ff 48 89 04 24 | |
RSP: 002b:00007ffdb4aadbe8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 | |
RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f5538c101b0 | |
RDX: 000000000000000a RSI: 00007f553b13ccbe RDI: 0000000000000003 | |
RBP: 00007f553b13ccbe R08: 00007ffdb4aadba0 R09: 0000000000000000 | |
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003 | |
R13: 0000000000000000 R14: ffffffffffffffff R15: 00007ffdb4aadea0 | |
</TASK> | |
============================= | |
[ BUG: Invalid wait context ] | |
6.2.0 #1 Tainted: G W | |
----------------------------- | |
(agetty)/9817 is trying to lock: | |
ffff888017129278 (&helper->lock){+.+.}-{3:3}, at: drm_fb_helper_pan_display+0xdb/0x980 drivers/gpu/drm/drm_fb_helper.c:1712 | |
other info that might help us debug this: | |
context-{4:4} | |
4 locks held by (agetty)/9817: | |
#0: ffff888017797098 (&tty->ldisc_sem){++++}-{0:0}, at: tty_ldisc_ref_wait+0x27/0x80 drivers/tty/tty_ldisc.c:244 | |
#1: ffff888017797130 (&tty->atomic_write_lock){+.+.}-{3:3}, at: tty_write_lock+0x23/0x90 drivers/tty/tty_io.c:944 | |
#2: ffff888046ee93e0 (&gsm->tx_lock){....}-{2:2}, at: gsmld_write+0x63/0x150 drivers/tty/n_gsm.c:3410 | |
#3: ffffffff8c780ee0 (console_lock){+.+.}-{0:0}, at: do_con_write+0x114/0x1e40 drivers/tty/vt/vt.c:2908 | |
stack backtrace: | |
CPU: 0 PID: 9817 Comm: (agetty) Tainted: G W 6.2.0 #1 | |
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 | |
Call Trace: | |
<TASK> | |
__dump_stack lib/dump_stack.c:88 [inline] | |
dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 | |
print_lock_invalid_wait_context kernel/locking/lockdep.c:4707 [inline] | |
check_wait_context kernel/locking/lockdep.c:4768 [inline] | |
__lock_acquire.cold+0x23b/0x3c3 kernel/locking/lockdep.c:5005 | |
lock_acquire kernel/locking/lockdep.c:5668 [inline] | |
lock_acquire+0x1df/0x640 kernel/locking/lockdep.c:5633 | |
__mutex_lock_common kernel/locking/mutex.c:603 [inline] | |
__mutex_lock+0x154/0x22f0 kernel/locking/mutex.c:747 | |
drm_fb_helper_pan_display+0xdb/0x980 drivers/gpu/drm/drm_fb_helper.c:1712 | |
fb_pan_display+0x2fc/0x6c0 drivers/video/fbdev/core/fbmem.c:925 | |
bit_update_start+0x4a/0x1f0 drivers/video/fbdev/core/bitblit.c:387 | |
fbcon_switch+0xc01/0x12b0 drivers/video/fbdev/core/fbcon.c:2174 | |
flush_scrollback drivers/tty/vt/vt.c:964 [inline] | |
csi_J+0x8fb/0xab0 drivers/tty/vt/vt.c:1573 | |
do_con_trol+0x51ea/0x5650 drivers/tty/vt/vt.c:2454 | |
do_con_write+0xf0b/0x1e40 drivers/tty/vt/vt.c:2951 | |
con_write+0x26/0x40 drivers/tty/vt/vt.c:3295 | |
gsmld_write+0xd0/0x150 drivers/tty/n_gsm.c:3413 | |
do_tty_write drivers/tty/tty_io.c:1018 [inline] | |
file_tty_write.isra.0+0x48f/0x820 drivers/tty/tty_io.c:1089 | |
call_write_iter include/linux/fs.h:2189 [inline] | |
new_sync_write fs/read_write.c:491 [inline] | |
vfs_write+0x9cf/0xd90 fs/read_write.c:584 | |
ksys_write+0x12c/0x250 fs/read_write.c:637 | |
do_syscall_x64 arch/x86/entry/common.c:50 [inline] | |
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 | |
entry_SYSCALL_64_after_hwframe+0x63/0xcd | |
RIP: 0033:0x7f5538c101b0 | |
Code: 2e 0f 1f 84 00 00 00 00 00 90 48 8b 05 19 7e 20 00 c3 0f 1f 84 00 00 00 00 00 83 3d 19 c2 20 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 ae fc ff ff 48 89 04 24 | |
RSP: 002b:00007ffdb4aadbe8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 | |
RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f5538c101b0 | |
RDX: 000000000000000a RSI: 00007f553b13ccbe RDI: 0000000000000003 | |
RBP: 00007f553b13ccbe R08: 00007ffdb4aadba0 R09: 0000000000000000 | |
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003 | |
R13: 0000000000000000 R14: ffffffffffffffff R15: 00007ffdb4aadea0 | |
</TASK> | |
------------[ cut here ]------------ | |
raw_local_irq_restore() called with IRQs enabled | |
WARNING: CPU: 0 PID: 9817 at kernel/locking/irqflag-debug.c:10 warn_bogus_irq_restore+0x1d/0x20 kernel/locking/irqflag-debug.c:10 | |
Modules linked in: | |
CPU: 0 PID: 9817 Comm: (agetty) Tainted: G W 6.2.0 #1 | |
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 | |
RIP: 0010:warn_bogus_irq_restore+0x1d/0x20 kernel/locking/irqflag-debug.c:10 | |
Code: ba ff cc cc cc cc cc cc cc cc cc cc cc 80 3d 7c 25 4e 04 00 74 01 c3 48 c7 c7 e0 d7 4c 8a c6 05 6b 25 4e 04 01 e8 25 c1 ba ff <0f> 0b c3 44 8b 05 55 85 63 04 55 53 65 48 8b 1c 25 80 9d 03 00 45 | |
RSP: 0018:ffffc9000ecc7ca0 EFLAGS: 00010282 | |
RAX: 0000000000000000 RBX: 0000000000000200 RCX: 0000000000000000 | |
RDX: 0000000000000000 RSI: ffff88804b890000 RDI: fffff52001d98f86 | |
RBP: ffff888046ee93c8 R08: 0000000000000000 R09: ffffed1005944f32 | |
R10: ffff88802ca2798b R11: ffffed1005944f31 R12: ffff888046ee93c8 | |
R13: 000000000000000a R14: 0000000000000282 R15: ffff888016e81000 | |
FS: 00007f553b6dd500(0000) GS:ffff88802ca00000(0000) knlGS:0000000000000000 | |
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | |
CR2: 0000558d7f19eee0 CR3: 000000004e43c000 CR4: 0000000000350ef0 | |
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | |
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | |
Call Trace: | |
<TASK> | |
__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:151 [inline] | |
_raw_spin_unlock_irqrestore+0x64/0x70 kernel/locking/spinlock.c:194 | |
spin_unlock_irqrestore include/linux/spinlock.h:405 [inline] | |
gsmld_write+0xe3/0x150 drivers/tty/n_gsm.c:3416 | |
do_tty_write drivers/tty/tty_io.c:1018 [inline] | |
file_tty_write.isra.0+0x48f/0x820 drivers/tty/tty_io.c:1089 | |
call_write_iter include/linux/fs.h:2189 [inline] | |
new_sync_write fs/read_write.c:491 [inline] | |
vfs_write+0x9cf/0xd90 fs/read_write.c:584 | |
ksys_write+0x12c/0x250 fs/read_write.c:637 | |
do_syscall_x64 arch/x86/entry/common.c:50 [inline] | |
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 | |
entry_SYSCALL_64_after_hwframe+0x63/0xcd | |
RIP: 0033:0x7f5538c101b0 | |
Code: 2e 0f 1f 84 00 00 00 00 00 90 48 8b 05 19 7e 20 00 c3 0f 1f 84 00 00 00 00 00 83 3d 19 c2 20 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 ae fc ff ff 48 89 04 24 | |
RSP: 002b:00007ffdb4aadbe8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 | |
RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f5538c101b0 | |
RDX: 000000000000000a RSI: 00007f553b13ccbe RDI: 0000000000000003 | |
RBP: 00007f553b13ccbe R08: 00007ffdb4aadba0 R09: 0000000000000000 | |
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003 | |
R13: 0000000000000000 R14: ffffffffffffffff R15: 00007ffdb4aadea0 | |
</TASK> | |
Syzkaller reproducer: | |
# {Threaded:true Collide:true Repeat:true RepeatTimes:0 Procs:1 Slowdown:1 Sandbox: Leak:false NetInjection:false NetDevices:false NetReset:false Cgroups:false BinfmtMisc:false CloseFDs:false KCSAN:false DevlinkPCI:false USB:false VhciInjection:false Wifi:false IEEE802154:false Sysctl:false UseTmpDir:false HandleSegv:false Repro:false Trace:false LegacyOptions:{Fault:false FaultCall:0 FaultNth:0} InitResource:false} | |
r0 = syz_open_dev$ptys_syzgen(&(0x7f0000000100), 0x0, 0x0) | |
ioctl$ptmx_Group5423_1(r0, 0x5423, &(0x7f0000000000)=0x15) | |
C reproducer: | |
// autogenerated by syzkaller (https://github.com/google/syzkaller) | |
#define _GNU_SOURCE | |
#include <dirent.h> | |
#include <endian.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <pthread.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> | |
#include <linux/futex.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 thread_start(void* (*fn)(void*), void* arg) | |
{ | |
pthread_t th; | |
pthread_attr_t attr; | |
pthread_attr_init(&attr); | |
pthread_attr_setstacksize(&attr, 128 << 10); | |
int i = 0; | |
for (; i < 100; i++) { | |
if (pthread_create(&th, &attr, fn, arg) == 0) { | |
pthread_attr_destroy(&attr); | |
return; | |
} | |
if (errno == EAGAIN) { | |
usleep(50); | |
continue; | |
} | |
break; | |
} | |
exit(1); | |
} | |
typedef struct { | |
int state; | |
} event_t; | |
static void event_init(event_t* ev) | |
{ | |
ev->state = 0; | |
} | |
static void event_reset(event_t* ev) | |
{ | |
ev->state = 0; | |
} | |
static void event_set(event_t* ev) | |
{ | |
if (ev->state) | |
exit(1); | |
__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); | |
syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000); | |
} | |
static void event_wait(event_t* ev) | |
{ | |
while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) | |
syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); | |
} | |
static int event_isset(event_t* ev) | |
{ | |
return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); | |
} | |
static int event_timedwait(event_t* ev, uint64_t timeout) | |
{ | |
uint64_t start = current_time_ms(); | |
uint64_t now = start; | |
for (;;) { | |
uint64_t remain = timeout - (now - start); | |
struct timespec ts; | |
ts.tv_sec = remain / 1000; | |
ts.tv_nsec = (remain % 1000) * 1000 * 1000; | |
syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts); | |
if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) | |
return 1; | |
now = current_time_ms(); | |
if (now - start > timeout) | |
return 0; | |
} | |
} | |
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"); | |
} | |
struct thread_t { | |
int created, call; | |
event_t ready, done; | |
}; | |
static struct thread_t threads[16]; | |
static void execute_call(int call); | |
static int running; | |
static void* thr(void* arg) | |
{ | |
struct thread_t* th = (struct thread_t*)arg; | |
for (;;) { | |
event_wait(&th->ready); | |
event_reset(&th->ready); | |
execute_call(th->call); | |
__atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); | |
event_set(&th->done); | |
} | |
return 0; | |
} | |
static void execute_one(void) | |
{ | |
int i, call, thread; | |
int collide = 0; | |
again: | |
for (call = 0; call < 2; call++) { | |
for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); | |
thread++) { | |
struct thread_t* th = &threads[thread]; | |
if (!th->created) { | |
th->created = 1; | |
event_init(&th->ready); | |
event_init(&th->done); | |
event_set(&th->done); | |
thread_start(thr, th); | |
} | |
if (!event_isset(&th->done)) | |
continue; | |
event_reset(&th->done); | |
th->call = call; | |
__atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); | |
event_set(&th->ready); | |
if (collide && (call % 2) == 0) | |
break; | |
event_timedwait(&th->done, 50); | |
break; | |
} | |
} | |
for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) | |
sleep_ms(1); | |
if (!collide) { | |
collide = 1; | |
goto again; | |
} | |
} | |
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_call(int call) | |
{ | |
intptr_t res = 0; | |
switch (call) { | |
case 0: | |
memcpy((void*)0x20000100, "/dev/tty#\000", 10); | |
res = -1; | |
res = syz_open_dev(0x20000100, 0, 0); | |
if (res != -1) | |
r[0] = res; | |
break; | |
case 1: | |
*(uint32_t*)0x20000000 = 0x15; | |
syscall(__NR_ioctl, r[0], 0x5423, 0x20000000ul); | |
break; | |
} | |
} | |
int main(void) | |
{ | |
syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); | |
syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul); | |
syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul); | |
loop(); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment