Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
693 changed files
with
478,899 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.norepro | ||
*.syz |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,357 @@ | ||
// INFO: task hung in nbd_ioctl | ||
// https://syzkaller.appspot.com/bug?id=0003deaa9f80de950cb6e0d2cb04c59b4f33a928 | ||
// status:fixed | ||
// 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 <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/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/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> | ||
|
||
static __thread int skip_segv; | ||
static __thread jmp_buf segv_env; | ||
|
||
static void segv_handler(int sig, siginfo_t* info, void* ctx) | ||
{ | ||
uintptr_t addr = (uintptr_t)info->si_addr; | ||
const uintptr_t prog_start = 1 << 20; | ||
const uintptr_t prog_end = 100 << 20; | ||
if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && | ||
(addr < prog_start || addr > prog_end)) { | ||
_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(...) \ | ||
{ \ | ||
__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ | ||
if (_setjmp(segv_env) == 0) { \ | ||
__VA_ARGS__; \ | ||
} \ | ||
__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ | ||
} | ||
|
||
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 struct { | ||
char* pos; | ||
int nesting; | ||
struct nlattr* nested[8]; | ||
char buf[1024]; | ||
} nlmsg; | ||
|
||
static void netlink_init(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(int typ, const void* data, int size) | ||
{ | ||
struct nlattr* attr = (struct nlattr*)nlmsg.pos; | ||
attr->nla_len = sizeof(*attr) + size; | ||
attr->nla_type = typ; | ||
memcpy(attr + 1, data, size); | ||
nlmsg.pos += NLMSG_ALIGN(attr->nla_len); | ||
} | ||
|
||
static int netlink_send_ext(int sock, uint16_t reply_type, int* reply_len) | ||
{ | ||
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; | ||
unsigned n = sendto(sock, nlmsg.buf, hdr->nlmsg_len, 0, | ||
(struct sockaddr*)&addr, sizeof(addr)); | ||
if (n != hdr->nlmsg_len) | ||
exit(1); | ||
n = recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0); | ||
if (n < sizeof(struct nlmsghdr)) | ||
exit(1); | ||
if (reply_len && hdr->nlmsg_type == reply_type) { | ||
*reply_len = n; | ||
return 0; | ||
} | ||
if (n < sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr)) | ||
exit(1); | ||
if (hdr->nlmsg_type != NLMSG_ERROR) | ||
exit(1); | ||
return -((struct nlmsgerr*)(hdr + 1))->error; | ||
} | ||
|
||
static int netlink_send(int sock) | ||
{ | ||
return netlink_send_ext(sock, 0, NULL); | ||
} | ||
|
||
const int kInitNetNsFd = 239; | ||
|
||
#define DEVLINK_FAMILY_NAME "devlink" | ||
|
||
#define DEVLINK_CMD_RELOAD 37 | ||
#define DEVLINK_ATTR_BUS_NAME 1 | ||
#define DEVLINK_ATTR_DEV_NAME 2 | ||
#define DEVLINK_ATTR_NETNS_FD 137 | ||
|
||
static void netlink_devlink_netns_move(const char* bus_name, | ||
const char* dev_name, int netns_fd) | ||
{ | ||
struct genlmsghdr genlhdr; | ||
struct nlattr* attr; | ||
int sock, err, n; | ||
uint16_t id = 0; | ||
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
if (sock == -1) | ||
exit(1); | ||
memset(&genlhdr, 0, sizeof(genlhdr)); | ||
genlhdr.cmd = CTRL_CMD_GETFAMILY; | ||
netlink_init(GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr)); | ||
netlink_attr(CTRL_ATTR_FAMILY_NAME, DEVLINK_FAMILY_NAME, | ||
strlen(DEVLINK_FAMILY_NAME) + 1); | ||
err = netlink_send_ext(sock, GENL_ID_CTRL, &n); | ||
if (err) { | ||
goto error; | ||
} | ||
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) { | ||
goto error; | ||
} | ||
recv(sock, nlmsg.buf, sizeof(nlmsg.buf), 0); /* recv ack */ | ||
memset(&genlhdr, 0, sizeof(genlhdr)); | ||
genlhdr.cmd = DEVLINK_CMD_RELOAD; | ||
netlink_init(id, 0, &genlhdr, sizeof(genlhdr)); | ||
netlink_attr(DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
netlink_attr(DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
netlink_attr(DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd)); | ||
netlink_send(sock); | ||
error: | ||
close(sock); | ||
} | ||
|
||
static void initialize_devlink_pci(void) | ||
{ | ||
int netns = open("/proc/self/ns/net", O_RDONLY); | ||
if (netns == -1) | ||
exit(1); | ||
int ret = setns(kInitNetNsFd, 0); | ||
if (ret == -1) | ||
exit(1); | ||
netlink_devlink_netns_move("pci", "0000:00:10.0", netns); | ||
ret = setns(netns, 0); | ||
if (ret == -1) | ||
exit(1); | ||
close(netns); | ||
} | ||
|
||
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; | ||
NONFAILING(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); | ||
int i; | ||
for (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 execute_one(void); | ||
|
||
#define WAIT_FLAGS __WALL | ||
|
||
static void loop(void) | ||
{ | ||
int iter; | ||
for (iter = 0;; 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 < 5 * 1000) | ||
continue; | ||
kill_and_wait(pid, &status); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
||
void execute_one(void) | ||
{ | ||
intptr_t res = 0; | ||
res = syscall(__NR_socket, 0x10, 2, 0); | ||
if (res != -1) | ||
r[0] = res; | ||
NONFAILING(memcpy((void*)0x200001c0, "/dev/nbd#\000", 10)); | ||
res = syz_open_dev(0x200001c0, 0, 0); | ||
if (res != -1) | ||
r[1] = res; | ||
res = syz_open_dev(0, 0, 0); | ||
if (res != -1) | ||
r[2] = res; | ||
syscall(__NR_ioctl, r[1], 0xab00, r[0]); | ||
syscall(__NR_ioctl, r[2], 0xab03, 0); | ||
} | ||
int main(void) | ||
{ | ||
syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); | ||
install_segv_handler(); | ||
loop(); | ||
return 0; | ||
} |
Oops, something went wrong.