-
-
Save freexxxyyy/5f0c95e95e1bc0fb681e504114b61de8 to your computer and use it in GitHub Desktop.
WARNING in free_pgtables
This file contains hidden or 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
// autogenerated by syzkaller (https://github.com/google/syzkaller) | |
#define _GNU_SOURCE | |
#include <arpa/inet.h> | |
#include <dirent.h> | |
#include <endian.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <net/if.h> | |
#include <netinet/in.h> | |
#include <pthread.h> | |
#include <setjmp.h> | |
#include <signal.h> | |
#include <stdarg.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#include <sys/prctl.h> | |
#include <sys/socket.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> | |
#include <linux/genetlink.h> | |
#include <linux/if_addr.h> | |
#include <linux/if_link.h> | |
#include <linux/in6.h> | |
#include <linux/neighbour.h> | |
#include <linux/net.h> | |
#include <linux/netlink.h> | |
#include <linux/rtnetlink.h> | |
#include <linux/veth.h> | |
#ifndef __NR_io_uring_enter | |
#define __NR_io_uring_enter 426 | |
#endif | |
#ifndef __NR_io_uring_setup | |
#define __NR_io_uring_setup 425 | |
#endif | |
static __thread int clone_ongoing; | |
static __thread int skip_segv; | |
static __thread jmp_buf segv_env; | |
static void segv_handler(int sig, siginfo_t* info, void* ctx) | |
{ | |
if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) { | |
exit(sig); | |
} | |
uintptr_t addr = (uintptr_t)info->si_addr; | |
const uintptr_t prog_start = 1 << 20; | |
const uintptr_t prog_end = 100 << 20; | |
int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0; | |
int valid = addr < prog_start || addr > prog_end; | |
if (skip && valid) { | |
_longjmp(segv_env, 1); | |
} | |
exit(sig); | |
} | |
static void install_segv_handler(void) | |
{ | |
struct sigaction sa; | |
memset(&sa, 0, sizeof(sa)); | |
sa.sa_handler = SIG_IGN; | |
syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); | |
syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); | |
memset(&sa, 0, sizeof(sa)); | |
sa.sa_sigaction = segv_handler; | |
sa.sa_flags = SA_NODEFER | SA_SIGINFO; | |
sigaction(SIGSEGV, &sa, NULL); | |
sigaction(SIGBUS, &sa, NULL); | |
} | |
#define NONFAILING(...) \ | |
({ \ | |
int ok = 1; \ | |
__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ | |
if (_setjmp(segv_env) == 0) { \ | |
__VA_ARGS__; \ | |
} else \ | |
ok = 0; \ | |
__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ | |
ok; \ | |
}) | |
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; | |
} | |
struct nlmsg { | |
char* pos; | |
int nesting; | |
struct nlattr* nested[8]; | |
char buf[4096]; | |
}; | |
static void netlink_init(struct nlmsg* nlmsg, int typ, int flags, | |
const void* data, int size) | |
{ | |
memset(nlmsg, 0, sizeof(*nlmsg)); | |
struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; | |
hdr->nlmsg_type = typ; | |
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; | |
memcpy(hdr + 1, data, size); | |
nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size); | |
} | |
static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data, | |
int size) | |
{ | |
struct nlattr* attr = (struct nlattr*)nlmsg->pos; | |
attr->nla_len = sizeof(*attr) + size; | |
attr->nla_type = typ; | |
if (size > 0) | |
memcpy(attr + 1, data, size); | |
nlmsg->pos += NLMSG_ALIGN(attr->nla_len); | |
} | |
static void netlink_nest(struct nlmsg* nlmsg, int typ) | |
{ | |
struct nlattr* attr = (struct nlattr*)nlmsg->pos; | |
attr->nla_type = typ; | |
nlmsg->pos += sizeof(*attr); | |
nlmsg->nested[nlmsg->nesting++] = attr; | |
} | |
static void netlink_done(struct nlmsg* nlmsg) | |
{ | |
struct nlattr* attr = nlmsg->nested[--nlmsg->nesting]; | |
attr->nla_len = nlmsg->pos - (char*)attr; | |
} | |
static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type, | |
int* reply_len, bool dofail) | |
{ | |
if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting) | |
exit(1); | |
struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf; | |
hdr->nlmsg_len = nlmsg->pos - nlmsg->buf; | |
struct sockaddr_nl addr; | |
memset(&addr, 0, sizeof(addr)); | |
addr.nl_family = AF_NETLINK; | |
ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, | |
(struct sockaddr*)&addr, sizeof(addr)); | |
if (n != (ssize_t)hdr->nlmsg_len) { | |
if (dofail) | |
exit(1); | |
return -1; | |
} | |
n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); | |
if (reply_len) | |
*reply_len = 0; | |
if (n < 0) { | |
if (dofail) | |
exit(1); | |
return -1; | |
} | |
if (n < (ssize_t)sizeof(struct nlmsghdr)) { | |
errno = EINVAL; | |
if (dofail) | |
exit(1); | |
return -1; | |
} | |
if (hdr->nlmsg_type == NLMSG_DONE) | |
return 0; | |
if (reply_len && hdr->nlmsg_type == reply_type) { | |
*reply_len = n; | |
return 0; | |
} | |
if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) { | |
errno = EINVAL; | |
if (dofail) | |
exit(1); | |
return -1; | |
} | |
if (hdr->nlmsg_type != NLMSG_ERROR) { | |
errno = EINVAL; | |
if (dofail) | |
exit(1); | |
return -1; | |
} | |
errno = -((struct nlmsgerr*)(hdr + 1))->error; | |
return -errno; | |
} | |
static int netlink_send(struct nlmsg* nlmsg, int sock) | |
{ | |
return netlink_send_ext(nlmsg, sock, 0, NULL, true); | |
} | |
static int netlink_query_family_id(struct nlmsg* nlmsg, int sock, | |
const char* family_name, bool dofail) | |
{ | |
struct genlmsghdr genlhdr; | |
memset(&genlhdr, 0, sizeof(genlhdr)); | |
genlhdr.cmd = CTRL_CMD_GETFAMILY; | |
netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr)); | |
netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name, | |
strnlen(family_name, GENL_NAMSIZ - 1) + 1); | |
int n = 0; | |
int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail); | |
if (err < 0) { | |
return -1; | |
} | |
uint16_t id = 0; | |
struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN + | |
NLMSG_ALIGN(sizeof(genlhdr))); | |
for (; (char*)attr < nlmsg->buf + n; | |
attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { | |
if (attr->nla_type == CTRL_ATTR_FAMILY_ID) { | |
id = *(uint16_t*)(attr + 1); | |
break; | |
} | |
} | |
if (!id) { | |
errno = EINVAL; | |
return -1; | |
} | |
recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); | |
return id; | |
} | |
static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type, | |
const char* name, bool up) | |
{ | |
struct ifinfomsg hdr; | |
memset(&hdr, 0, sizeof(hdr)); | |
if (up) | |
hdr.ifi_flags = hdr.ifi_change = IFF_UP; | |
netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, | |
sizeof(hdr)); | |
if (name) | |
netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name)); | |
netlink_nest(nlmsg, IFLA_LINKINFO); | |
netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type)); | |
} | |
static void netlink_device_change(struct nlmsg* nlmsg, int sock, | |
const char* name, bool up, const char* master, | |
const void* mac, int macsize, | |
const char* new_name) | |
{ | |
struct ifinfomsg hdr; | |
memset(&hdr, 0, sizeof(hdr)); | |
if (up) | |
hdr.ifi_flags = hdr.ifi_change = IFF_UP; | |
hdr.ifi_index = if_nametoindex(name); | |
netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr)); | |
if (new_name) | |
netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name)); | |
if (master) { | |
int ifindex = if_nametoindex(master); | |
netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex)); | |
} | |
if (macsize) | |
netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize); | |
int err = netlink_send(nlmsg, sock); | |
if (err < 0) { | |
} | |
} | |
static struct nlmsg nlmsg; | |
#define SIZEOF_IO_URING_SQE 64 | |
#define SIZEOF_IO_URING_CQE 16 | |
#define SQ_HEAD_OFFSET 0 | |
#define SQ_TAIL_OFFSET 64 | |
#define SQ_RING_MASK_OFFSET 256 | |
#define SQ_RING_ENTRIES_OFFSET 264 | |
#define SQ_FLAGS_OFFSET 276 | |
#define SQ_DROPPED_OFFSET 272 | |
#define CQ_HEAD_OFFSET 128 | |
#define CQ_TAIL_OFFSET 192 | |
#define CQ_RING_MASK_OFFSET 260 | |
#define CQ_RING_ENTRIES_OFFSET 268 | |
#define CQ_RING_OVERFLOW_OFFSET 284 | |
#define CQ_FLAGS_OFFSET 280 | |
#define CQ_CQES_OFFSET 320 | |
struct io_sqring_offsets { | |
uint32_t head; | |
uint32_t tail; | |
uint32_t ring_mask; | |
uint32_t ring_entries; | |
uint32_t flags; | |
uint32_t dropped; | |
uint32_t array; | |
uint32_t resv1; | |
uint64_t resv2; | |
}; | |
struct io_cqring_offsets { | |
uint32_t head; | |
uint32_t tail; | |
uint32_t ring_mask; | |
uint32_t ring_entries; | |
uint32_t overflow; | |
uint32_t cqes; | |
uint64_t resv[2]; | |
}; | |
struct io_uring_params { | |
uint32_t sq_entries; | |
uint32_t cq_entries; | |
uint32_t flags; | |
uint32_t sq_thread_cpu; | |
uint32_t sq_thread_idle; | |
uint32_t features; | |
uint32_t resv[4]; | |
struct io_sqring_offsets sq_off; | |
struct io_cqring_offsets cq_off; | |
}; | |
#define IORING_OFF_SQ_RING 0 | |
#define IORING_OFF_SQES 0x10000000ULL | |
#define IORING_SETUP_SQE128 (1U << 10) | |
#define IORING_SETUP_CQE32 (1U << 11) | |
static long syz_io_uring_setup(volatile long a0, volatile long a1, | |
volatile long a2, volatile long a3) | |
{ | |
uint32_t entries = (uint32_t)a0; | |
struct io_uring_params* setup_params = (struct io_uring_params*)a1; | |
void** ring_ptr_out = (void**)a2; | |
void** sqes_ptr_out = (void**)a3; | |
setup_params->flags &= ~(IORING_SETUP_CQE32 | IORING_SETUP_SQE128); | |
uint32_t fd_io_uring = syscall(__NR_io_uring_setup, entries, setup_params); | |
uint32_t sq_ring_sz = | |
setup_params->sq_off.array + setup_params->sq_entries * sizeof(uint32_t); | |
uint32_t cq_ring_sz = setup_params->cq_off.cqes + | |
setup_params->cq_entries * SIZEOF_IO_URING_CQE; | |
uint32_t ring_sz = sq_ring_sz > cq_ring_sz ? sq_ring_sz : cq_ring_sz; | |
*ring_ptr_out = | |
mmap(0, ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, | |
fd_io_uring, IORING_OFF_SQ_RING); | |
uint32_t sqes_sz = setup_params->sq_entries * SIZEOF_IO_URING_SQE; | |
*sqes_ptr_out = mmap(0, sqes_sz, PROT_READ | PROT_WRITE, | |
MAP_SHARED | MAP_POPULATE, fd_io_uring, IORING_OFF_SQES); | |
uint32_t* array = | |
(uint32_t*)((uintptr_t)*ring_ptr_out + setup_params->sq_off.array); | |
for (uint32_t index = 0; index < entries; index++) | |
array[index] = index; | |
return fd_io_uring; | |
} | |
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() | |
{ | |
int cad_pid = fork(); | |
if (cad_pid < 0) | |
exit(1); | |
if (cad_pid == 0) { | |
for (;;) | |
sleep(100); | |
} | |
char tmppid[32]; | |
snprintf(tmppid, sizeof(tmppid), "%d", cad_pid); | |
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", tmppid}, | |
}; | |
for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) { | |
if (!write_file(files[i].name, files[i].data)) { | |
} | |
} | |
kill(cad_pid, SIGKILL); | |
while (waitpid(cad_pid, NULL, 0) != cad_pid) | |
; | |
} | |
#define NL802154_CMD_SET_SHORT_ADDR 11 | |
#define NL802154_ATTR_IFINDEX 3 | |
#define NL802154_ATTR_SHORT_ADDR 10 | |
static const char* setup_802154() | |
{ | |
const char* error = NULL; | |
int sock_generic = -1; | |
int sock_route = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
if (sock_route == -1) { | |
error = "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) failed"; | |
goto fail; | |
} | |
sock_generic = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | |
if (sock_generic == -1) { | |
error = "socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC) failed"; | |
goto fail; | |
} | |
{ | |
int nl802154_family_id = | |
netlink_query_family_id(&nlmsg, sock_generic, "nl802154", true); | |
if (nl802154_family_id < 0) { | |
error = "netlink_query_family_id failed"; | |
goto fail; | |
} | |
for (int i = 0; i < 2; i++) { | |
char devname[] = "wpan0"; | |
devname[strlen(devname) - 1] += i; | |
uint64_t hwaddr = 0xaaaaaaaaaaaa0002 + (i << 8); | |
uint16_t shortaddr = 0xaaa0 + i; | |
int ifindex = if_nametoindex(devname); | |
struct genlmsghdr genlhdr; | |
memset(&genlhdr, 0, sizeof(genlhdr)); | |
genlhdr.cmd = NL802154_CMD_SET_SHORT_ADDR; | |
netlink_init(&nlmsg, nl802154_family_id, 0, &genlhdr, sizeof(genlhdr)); | |
netlink_attr(&nlmsg, NL802154_ATTR_IFINDEX, &ifindex, sizeof(ifindex)); | |
netlink_attr(&nlmsg, NL802154_ATTR_SHORT_ADDR, &shortaddr, | |
sizeof(shortaddr)); | |
if (netlink_send(&nlmsg, sock_generic) < 0) { | |
error = "NL802154_CMD_SET_SHORT_ADDR failed"; | |
goto fail; | |
} | |
netlink_device_change(&nlmsg, sock_route, devname, true, 0, &hwaddr, | |
sizeof(hwaddr), 0); | |
if (i == 0) { | |
netlink_add_device_impl(&nlmsg, "lowpan", "lowpan0", false); | |
netlink_done(&nlmsg); | |
netlink_attr(&nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex)); | |
if (netlink_send(&nlmsg, sock_route) < 0) { | |
error = "netlink: adding device lowpan0 type lowpan link wpan0"; | |
goto fail; | |
} | |
} | |
} | |
} | |
fail: | |
close(sock_route); | |
close(sock_generic); | |
return error; | |
} | |
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) | |
{ | |
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { | |
} | |
int i, call, thread; | |
for (call = 0; call < 15; 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); | |
event_timedwait(&th->done, 50); | |
break; | |
} | |
} | |
for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) | |
sleep_ms(1); | |
} | |
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 (;;) { | |
sleep_ms(10); | |
if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) | |
break; | |
if (current_time_ms() - start < 5000) | |
continue; | |
kill_and_wait(pid, &status); | |
break; | |
} | |
} | |
} | |
uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | |
void execute_call(int call) | |
{ | |
intptr_t res = 0; | |
switch (call) { | |
case 0: | |
NONFAILING(memcpy((void*)0x200003c0, "/dev/sg#\000", 9)); | |
NONFAILING(syz_open_dev(/*dev=*/0x200003c0, /*id=*/1, | |
/*flags=O_NOCTTY|FASYNC|0x100000*/ 0x102100)); | |
break; | |
case 1: | |
NONFAILING(*(uint32_t*)0x20000080 = -1); | |
NONFAILING(*(uint32_t*)0x20000084 = 0x80000001); | |
NONFAILING(*(uint32_t*)0x20000088 = 9); | |
NONFAILING(*(uint32_t*)0x2000008c = 5); | |
NONFAILING(*(uint8_t*)0x20000090 = 1); | |
NONFAILING(memcpy((void*)0x20000091, | |
"\x59\xa5\xc6\x49\x9e\x35\xbc\xa1\x40\xf0\x84\x27\x39\x3b" | |
"\x33\x68\x89\xf0\xcc", | |
19)); | |
NONFAILING(*(uint32_t*)0x200000a4 = 2); | |
NONFAILING(*(uint32_t*)0x200000a8 = 0x101); | |
syscall(__NR_ioctl, /*fd=*/-1, /*cmd=*/0x402c542d, /*arg=*/0x20000080ul); | |
break; | |
case 2: | |
NONFAILING(syz_open_dev(/*dev=*/0, /*id=*/0, /*flags=O_LARGEFILE*/ 0x8000)); | |
break; | |
case 3: | |
NONFAILING(memcpy((void*)0x20000140, "/dev/sg#\000", 9)); | |
res = -1; | |
NONFAILING(res = syz_open_dev(/*dev=*/0x20000140, /*id=*/0, | |
/*flags=O_LARGEFILE*/ 0x8000)); | |
if (res != -1) | |
r[0] = res; | |
break; | |
case 4: | |
NONFAILING(*(uint32_t*)0x20000080 = 0); | |
NONFAILING(*(uint32_t*)0x20000084 = 2); | |
NONFAILING(*(uint8_t*)0x20000088 = 0x85); | |
NONFAILING(*(uint8_t*)0x20000089 = 8); | |
NONFAILING(*(uint8_t*)0x2000008a = 0x15); | |
NONFAILING(*(uint8_t*)0x2000008b = 0xd); | |
syscall(__NR_ioctl, /*fd=*/r[0], /*arg0=*/1, /*arg1=*/0x20000080ul); | |
break; | |
case 5: | |
syscall(__NR_ioctl, /*fd=*/-1, /*arg0=*/1, /*arg1=*/0ul); | |
break; | |
case 6: | |
NONFAILING(syz_io_uring_setup(/*entries=*/0x142b, /*params=*/0, | |
/*ring_ptr=*/0x20000080, /*sqes_ptr=*/0)); | |
break; | |
case 7: | |
NONFAILING(syz_open_dev(/*dev=*/0xc, /*major=*/2, /*minor=*/0x14)); | |
break; | |
case 8: | |
syscall(__NR_ioctl, /*fd=*/-1, /*cmd=*/0x5423, /*arg=*/0ul); | |
break; | |
case 9: | |
res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0ul, | |
/*flags=O_RDWR*/ 2ul, 0); | |
if (res != -1) | |
r[1] = res; | |
break; | |
case 10: | |
syscall(__NR_ioctl, /*fd=*/r[1], /*arg0=*/0xc08c5332, /*arg1=*/0ul); | |
break; | |
case 11: | |
syscall(__NR_ioctl, /*fd=*/-1, /*arg0=*/0x2271, /*arg1=*/0ul); | |
break; | |
case 12: | |
syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0ul, | |
/*flags=O_SYNC|O_CLOEXEC|FASYNC|O_APPEND|O_WRONLY*/ 0x183401ul, | |
/*mode=*/0ul); | |
break; | |
case 13: | |
syscall(__NR_io_uring_enter, /*fd=*/-1, /*to_submit=*/0x7e66, | |
/*min_complete=*/0x7beb, | |
/*flags=IORING_ENTER_SQ_WAIT|IORING_ENTER_GETEVENTS*/ 5ul, | |
/*sigmask=*/0ul, /*size=*/0ul); | |
break; | |
case 14: | |
syscall(__NR_io_uring_enter, /*fd=*/-1, /*to_submit=*/0x7e66, | |
/*min_complete=*/0x7beb, | |
/*flags=IORING_ENTER_SQ_WAIT|IORING_ENTER_GETEVENTS*/ 5ul, | |
/*sigmask=*/0ul, /*size=*/0ul); | |
break; | |
} | |
} | |
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(); | |
const char* reason; | |
(void)reason; | |
if ((reason = setup_802154())) | |
printf("the reproducer may not work as expected: 802154 injection setup " | |
"failed: %s\n", | |
reason); | |
install_segv_handler(); | |
loop(); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment