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