1#!/bin/sh 2 3# "panic: inconsistent boundary count 2" seen. 4# Fixed by: 8321d0da2ce2 - main - kern/kern_thread.c: improve assert in thread_single_end() 5 6[ `uname -p` != "amd64" ] && exit 0 7 8. ../default.cfg 9cat > /tmp/syzkaller61.c <<EOF 10// https://syzkaller.appspot.com/bug?id=00d8ca63243899ffb67b15ec93aee4ffa2f06637 11// autogenerated by syzkaller (https://github.com/google/syzkaller) 12// Reported-by: syzbot+647212368c3f32c6f13f@syzkaller.appspotmail.com 13 14#define _GNU_SOURCE 15 16#include <sys/types.h> 17 18#include <errno.h> 19#include <pthread.h> 20#include <pwd.h> 21#include <setjmp.h> 22#include <signal.h> 23#include <stdarg.h> 24#include <stdbool.h> 25#include <stdint.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <sys/endian.h> 30#include <sys/syscall.h> 31#include <sys/wait.h> 32#include <time.h> 33#include <unistd.h> 34 35static __thread int clone_ongoing; 36static __thread int skip_segv; 37static __thread jmp_buf segv_env; 38 39static void segv_handler(int sig, siginfo_t* info, void* ctx __unused) 40{ 41 if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) { 42 exit(sig); 43 } 44 uintptr_t addr = (uintptr_t)info->si_addr; 45 const uintptr_t prog_start = 1 << 20; 46 const uintptr_t prog_end = 100 << 20; 47 int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0; 48 int valid = addr < prog_start || addr > prog_end; 49 if (sig == SIGBUS) 50 valid = 1; 51 if (skip && valid) { 52 _longjmp(segv_env, 1); 53 } 54 exit(sig); 55} 56 57static void install_segv_handler(void) 58{ 59 struct sigaction sa; 60 memset(&sa, 0, sizeof(sa)); 61 sa.sa_sigaction = segv_handler; 62 sa.sa_flags = SA_NODEFER | SA_SIGINFO; 63 sigaction(SIGSEGV, &sa, NULL); 64 sigaction(SIGBUS, &sa, NULL); 65} 66 67#define NONFAILING(...) \ 68 ({ \ 69 int ok = 1; \ 70 __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ 71 if (_setjmp(segv_env) == 0) { \ 72 __VA_ARGS__; \ 73 } else \ 74 ok = 0; \ 75 __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ 76 ok; \ 77 }) 78 79static void kill_and_wait(int pid, int* status) 80{ 81 kill(pid, SIGKILL); 82 while (waitpid(-1, status, 0) != pid) { 83 } 84} 85 86static void sleep_ms(uint64_t ms) 87{ 88 usleep(ms * 1000); 89} 90 91static uint64_t current_time_ms(void) 92{ 93 struct timespec ts; 94 if (clock_gettime(CLOCK_MONOTONIC, &ts)) 95 exit(1); 96 return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; 97} 98 99static void thread_start(void* (*fn)(void*), void* arg) 100{ 101 pthread_t th; 102 pthread_attr_t attr; 103 pthread_attr_init(&attr); 104 pthread_attr_setstacksize(&attr, 128 << 10); 105 int i = 0; 106 for (; i < 100; i++) { 107 if (pthread_create(&th, &attr, fn, arg) == 0) { 108 pthread_attr_destroy(&attr); 109 return; 110 } 111 if (errno == EAGAIN) { 112 usleep(50); 113 continue; 114 } 115 break; 116 } 117 exit(1); 118} 119 120typedef struct { 121 pthread_mutex_t mu; 122 pthread_cond_t cv; 123 int state; 124} event_t; 125 126static void event_init(event_t* ev) 127{ 128 if (pthread_mutex_init(&ev->mu, 0)) 129 exit(1); 130 if (pthread_cond_init(&ev->cv, 0)) 131 exit(1); 132 ev->state = 0; 133} 134 135static void event_reset(event_t* ev) 136{ 137 ev->state = 0; 138} 139 140static void event_set(event_t* ev) 141{ 142 pthread_mutex_lock(&ev->mu); 143 if (ev->state) 144 exit(1); 145 ev->state = 1; 146 pthread_mutex_unlock(&ev->mu); 147 pthread_cond_broadcast(&ev->cv); 148} 149 150static void event_wait(event_t* ev) 151{ 152 pthread_mutex_lock(&ev->mu); 153 while (!ev->state) 154 pthread_cond_wait(&ev->cv, &ev->mu); 155 pthread_mutex_unlock(&ev->mu); 156} 157 158static int event_isset(event_t* ev) 159{ 160 pthread_mutex_lock(&ev->mu); 161 int res = ev->state; 162 pthread_mutex_unlock(&ev->mu); 163 return res; 164} 165 166static int event_timedwait(event_t* ev, uint64_t timeout) 167{ 168 uint64_t start = current_time_ms(); 169 uint64_t now = start; 170 pthread_mutex_lock(&ev->mu); 171 for (;;) { 172 if (ev->state) 173 break; 174 uint64_t remain = timeout - (now - start); 175 struct timespec ts; 176 ts.tv_sec = remain / 1000; 177 ts.tv_nsec = (remain % 1000) * 1000 * 1000; 178 pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); 179 now = current_time_ms(); 180 if (now - start > timeout) 181 break; 182 } 183 int res = ev->state; 184 pthread_mutex_unlock(&ev->mu); 185 return res; 186} 187 188struct thread_t { 189 int created, call; 190 event_t ready, done; 191}; 192 193static struct thread_t threads[16]; 194static void execute_call(int call); 195static int running; 196 197static void* thr(void* arg) 198{ 199 struct thread_t* th = (struct thread_t*)arg; 200 for (;;) { 201 event_wait(&th->ready); 202 event_reset(&th->ready); 203 execute_call(th->call); 204 __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); 205 event_set(&th->done); 206 } 207 return 0; 208} 209 210static void execute_one(void) 211{ 212 int i, call, thread; 213 for (call = 0; call < 2; call++) { 214 for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); 215 thread++) { 216 struct thread_t* th = &threads[thread]; 217 if (!th->created) { 218 th->created = 1; 219 event_init(&th->ready); 220 event_init(&th->done); 221 event_set(&th->done); 222 thread_start(thr, th); 223 } 224 if (!event_isset(&th->done)) 225 continue; 226 event_reset(&th->done); 227 th->call = call; 228 __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); 229 event_set(&th->ready); 230 event_timedwait(&th->done, 50); 231 break; 232 } 233 } 234 for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) 235 sleep_ms(1); 236} 237 238static void execute_one(void); 239 240#define WAIT_FLAGS 0 241 242static void loop(void) 243{ 244 int iter __unused = 0; 245 for (;; iter++) { 246 int pid = fork(); 247 if (pid < 0) 248 exit(1); 249 if (pid == 0) { 250 execute_one(); 251 exit(0); 252 } 253 int status = 0; 254 uint64_t start = current_time_ms(); 255 for (;;) { 256 if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) 257 break; 258 sleep_ms(1); 259 if (current_time_ms() - start < 5000) 260 continue; 261 kill_and_wait(pid, &status); 262 break; 263 } 264 } 265} 266 267void execute_call(int call) 268{ 269 switch (call) { 270 case 0: 271 NONFAILING(*(uint32_t*)0x20001f00 = 0x16); /* SIGTTOU */ 272 NONFAILING(*(uint32_t*)0x20001f04 = 0); 273 NONFAILING(*(uint32_t*)0x20001f08 = 0); 274 NONFAILING(*(uint32_t*)0x20001f0c = 0); 275 NONFAILING(*(uint32_t*)0x20001f10 = 0); 276 NONFAILING(memset((void*)0x20001f14, 0, 60)); 277 syscall(SYS_procctl, 0ul, 0, 6ul, 0x20001f00ul); 278 break; 279 case 1: 280 syscall(SYS_rfork, 0x85000ul); 281 break; 282 } 283} 284int main(void) 285{ 286 syscall(SYS_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x1012ul, -1, 0ul); 287 install_segv_handler(); 288 loop(); 289 return 0; 290} 291EOF 292mycc -o /tmp/syzkaller61 -Wall -Wextra -O0 /tmp/syzkaller61.c -lpthread || 293 exit 1 294 295(cd ../testcases/swap; ./swap -t 3m -i 10 -l 100 > /dev/null 2>&1) & 296for i in `jot 300`; do 297 (cd /tmp; su -m $testuser -c ./syzkaller61) & 298 pids="$pids $!" 299done 300sleep 5 301kill -9 $pids 302wait $pids 303while pkill -9 syzkaller61; do :; done 304while pkill swap; do :; done 305wait 306 307rm -rf /tmp/syzkaller61 /tmp/syzkaller61.c /tmp/syzkaller61.core \ 308 /tmp/syzkaller.?????? 309exit 0 310