| @@ -0,0 +1,256 @@ | ||
| // Invalid request partialResult in splice | ||
| // https://syzkaller.appspot.com/bug?id=010ab5cdbd5d0ca73a4227be6e883bd65fec09bc | ||
| // status:fixed | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <endian.h> | ||
| #include <errno.h> | ||
| #include <pthread.h> | ||
| #include <setjmp.h> | ||
| #include <signal.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.h> | ||
| #include <time.h> | ||
| #include <unistd.h> | ||
|
|
||
| #include <linux/futex.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 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; | ||
| for (i = 0; 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); | ||
| } | ||
|
|
||
| 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_RELAXED)) | ||
| return 1; | ||
| now = current_time_ms(); | ||
| if (now - start > timeout) | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| 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 loop(void) | ||
| { | ||
| int i, call, thread; | ||
| for (call = 0; call < 6; 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, 45); | ||
| break; | ||
| } | ||
| } | ||
| for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) | ||
| sleep_ms(1); | ||
| } | ||
|
|
||
| uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| void execute_call(int call) | ||
| { | ||
| intptr_t res; | ||
| switch (call) { | ||
| case 0: | ||
| res = syscall(__NR_socketpair, 1, 5, 0, 0x200019c0); | ||
| if (res != -1) | ||
| NONFAILING(r[0] = *(uint32_t*)0x200019c0); | ||
| break; | ||
| case 1: | ||
| syscall(__NR_sendto, -1, 0, 0, 0, 0, 0); | ||
| break; | ||
| case 2: | ||
| res = syscall(__NR_pipe, 0x200002c0); | ||
| if (res != -1) { | ||
| NONFAILING(r[1] = *(uint32_t*)0x200002c0); | ||
| NONFAILING(r[2] = *(uint32_t*)0x200002c4); | ||
| } | ||
| break; | ||
| case 3: | ||
| syscall(__NR_splice, r[1], 0, r[0], 0, 0x420000a77, 0); | ||
| break; | ||
| case 4: | ||
| NONFAILING(*(uint32_t*)0x20000000 = 0x66); | ||
| NONFAILING(*(uint8_t*)0x20000004 = 0x7d); | ||
| NONFAILING(*(uint16_t*)0x20000005 = 2); | ||
| NONFAILING(*(uint16_t*)0x20000007 = 0); | ||
| NONFAILING(*(uint16_t*)0x20000009 = 0x5f); | ||
| NONFAILING(*(uint16_t*)0x2000000b = 0); | ||
| NONFAILING(*(uint32_t*)0x2000000d = 5); | ||
| NONFAILING(*(uint8_t*)0x20000011 = 2); | ||
| NONFAILING(*(uint32_t*)0x20000012 = 4); | ||
| NONFAILING(*(uint64_t*)0x20000016 = 2); | ||
| NONFAILING(*(uint32_t*)0x2000001e = 0x4000000); | ||
| NONFAILING(*(uint32_t*)0x20000022 = 0xcc); | ||
| NONFAILING(*(uint32_t*)0x20000026 = 0x3ff); | ||
| NONFAILING(*(uint64_t*)0x2000002a = 0xf057); | ||
| NONFAILING(*(uint16_t*)0x20000032 = 0xe); | ||
| NONFAILING(memcpy((void*)0x20000034, "wlan0Mmd5sum@)", 14)); | ||
| NONFAILING(*(uint16_t*)0x20000042 = 3); | ||
| NONFAILING(memcpy((void*)0x20000044, "!%/", 3)); | ||
| NONFAILING(*(uint16_t*)0x20000047 = 0x1b); | ||
| NONFAILING(memcpy((void*)0x20000049, "selinux\\!*proc-GPL*vboxnet0", 27)); | ||
| NONFAILING(*(uint16_t*)0x20000064 = 0); | ||
| syscall(__NR_write, r[2], 0x20000000, 0x66); | ||
| break; | ||
| case 5: | ||
| syscall(__NR_write, r[2], 0x20000000, 0xfffffd88); | ||
| break; | ||
| } | ||
| } | ||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); | ||
| install_segv_handler(); | ||
| loop(); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,374 @@ | ||
| // KASAN: user-memory-access Read in insert_char | ||
| // https://syzkaller.appspot.com/bug?id=01a2b05ebbe9be9802bcccfd2008e74cc3a55ed1 | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <endian.h> | ||
| #include <fcntl.h> | ||
| #include <net/if.h> | ||
| #include <netinet/in.h> | ||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.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> | ||
|
|
||
| struct nlmsg { | ||
| char* pos; | ||
| int nesting; | ||
| struct nlattr* nested[8]; | ||
| char buf[1024]; | ||
| }; | ||
|
|
||
| static struct nlmsg nlmsg; | ||
|
|
||
| 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; | ||
| memcpy(attr + 1, data, size); | ||
| nlmsg->pos += NLMSG_ALIGN(attr->nla_len); | ||
| } | ||
|
|
||
| static int netlink_send_ext(struct nlmsg* nlmsg, 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 (hdr->nlmsg_type == NLMSG_DONE) { | ||
| *reply_len = 0; | ||
| return 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(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| return netlink_send_ext(nlmsg, sock, 0, NULL); | ||
| } | ||
|
|
||
| static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset, | ||
| unsigned int total_len) | ||
| { | ||
| struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset); | ||
| if (offset == total_len || offset + hdr->nlmsg_len > total_len) | ||
| return -1; | ||
| return hdr->nlmsg_len; | ||
| } | ||
|
|
||
| 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); | ||
| (void)err; | ||
| } | ||
|
|
||
| const int kInitNetNsFd = 239; | ||
|
|
||
| #define DEVLINK_FAMILY_NAME "devlink" | ||
|
|
||
| #define DEVLINK_CMD_PORT_GET 5 | ||
| #define DEVLINK_CMD_RELOAD 37 | ||
| #define DEVLINK_ATTR_BUS_NAME 1 | ||
| #define DEVLINK_ATTR_DEV_NAME 2 | ||
| #define DEVLINK_ATTR_NETDEV_NAME 7 | ||
| #define DEVLINK_ATTR_NETNS_FD 138 | ||
|
|
||
| static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| struct nlattr* attr; | ||
| int err, n; | ||
| uint16_t id = 0; | ||
| 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, DEVLINK_FAMILY_NAME, | ||
| strlen(DEVLINK_FAMILY_NAME) + 1); | ||
| err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n); | ||
| if (err) { | ||
| return -1; | ||
| } | ||
| 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) { | ||
| return -1; | ||
| } | ||
| recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */ | ||
| return id; | ||
| } | ||
|
|
||
| static void netlink_devlink_netns_move(const char* bus_name, | ||
| const char* dev_name, int netns_fd) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int sock; | ||
| int id, err; | ||
| sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_RELOAD; | ||
| netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd)); | ||
| err = netlink_send(&nlmsg, sock); | ||
| if (err) { | ||
| } | ||
| error: | ||
| close(sock); | ||
| } | ||
|
|
||
| static struct nlmsg nlmsg2; | ||
|
|
||
| static void initialize_devlink_ports(const char* bus_name, const char* dev_name, | ||
| const char* netdev_prefix) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int len, total_len, id, err, offset; | ||
| uint16_t netdev_index; | ||
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
| if (rtsock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_PORT_GET; | ||
| netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| err = netlink_send_ext(&nlmsg, sock, id, &total_len); | ||
| if (err) { | ||
| goto error; | ||
| } | ||
| offset = 0; | ||
| netdev_index = 0; | ||
| while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) { | ||
| struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + | ||
| NLMSG_ALIGN(sizeof(genlhdr))); | ||
| for (; (char*)attr < nlmsg.buf + offset + len; | ||
| attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { | ||
| if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) { | ||
| char* port_name; | ||
| char netdev_name[IFNAMSIZ]; | ||
| port_name = (char*)(attr + 1); | ||
| snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, | ||
| netdev_index); | ||
| netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, | ||
| netdev_name); | ||
| break; | ||
| } | ||
| } | ||
| offset += len; | ||
| netdev_index++; | ||
| } | ||
| error: | ||
| close(rtsock); | ||
| 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); | ||
| initialize_devlink_ports("pci", "0000:00:10.0", "netpci"); | ||
| } | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
|
|
||
| uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| intptr_t res = 0; | ||
| memcpy((void*)0x20000180, "/dev/fb0\000", 9); | ||
| res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000180ul, 0ul, 0ul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| *(uint32_t*)0x20000000 = 0x356; | ||
| *(uint32_t*)0x20000004 = 0; | ||
| *(uint32_t*)0x20000008 = 0; | ||
| *(uint32_t*)0x2000000c = 0; | ||
| *(uint32_t*)0x20000010 = 0; | ||
| *(uint32_t*)0x20000014 = 0; | ||
| *(uint32_t*)0x20000018 = 8; | ||
| *(uint32_t*)0x2000001c = 0; | ||
| *(uint32_t*)0x20000020 = 0; | ||
| *(uint32_t*)0x20000024 = 0; | ||
| *(uint32_t*)0x20000028 = 0; | ||
| *(uint32_t*)0x2000002c = 0; | ||
| *(uint32_t*)0x20000030 = 0; | ||
| *(uint32_t*)0x20000034 = 0; | ||
| *(uint32_t*)0x20000038 = 0; | ||
| *(uint32_t*)0x2000003c = 0; | ||
| *(uint32_t*)0x20000040 = 0; | ||
| *(uint32_t*)0x20000044 = 0; | ||
| *(uint32_t*)0x20000048 = 0; | ||
| *(uint32_t*)0x2000004c = 0; | ||
| *(uint32_t*)0x20000050 = 0; | ||
| *(uint32_t*)0x20000054 = 0; | ||
| *(uint32_t*)0x20000058 = 0; | ||
| *(uint32_t*)0x2000005c = 0; | ||
| *(uint32_t*)0x20000060 = 0; | ||
| *(uint32_t*)0x20000064 = 0; | ||
| *(uint32_t*)0x20000068 = 0; | ||
| *(uint32_t*)0x2000006c = 0; | ||
| *(uint32_t*)0x20000070 = 0; | ||
| *(uint32_t*)0x20000074 = 0; | ||
| *(uint32_t*)0x20000078 = 0; | ||
| *(uint32_t*)0x2000007c = 0; | ||
| *(uint32_t*)0x20000080 = 0; | ||
| *(uint32_t*)0x20000084 = 0; | ||
| *(uint32_t*)0x20000088 = 0; | ||
| *(uint32_t*)0x2000008c = 0; | ||
| *(uint32_t*)0x20000090 = 0; | ||
| *(uint32_t*)0x20000094 = 0; | ||
| *(uint32_t*)0x20000098 = 0; | ||
| *(uint32_t*)0x2000009c = 0; | ||
| syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000000ul); | ||
| res = syz_open_dev(0xc, 4, 0x14); | ||
| if (res != -1) | ||
| r[1] = res; | ||
| *(uint8_t*)0x20000000 = 0xe; | ||
| *(uint8_t*)0x20000001 = 0x9b; | ||
| *(uint8_t*)0x20000002 = 0x3e; | ||
| *(uint8_t*)0x20000003 = 0x9b; | ||
| *(uint8_t*)0x20000004 = 0; | ||
| *(uint8_t*)0x20000005 = 0; | ||
| *(uint8_t*)0x20000006 = 0; | ||
| *(uint8_t*)0x20000007 = 0; | ||
| *(uint64_t*)0x20000008 = 0; | ||
| *(uint16_t*)0x20000010 = 0; | ||
| *(uint16_t*)0x20000012 = 0; | ||
| *(uint32_t*)0x20000014 = 0; | ||
| *(uint64_t*)0x20000018 = 0; | ||
| *(uint64_t*)0x20000020 = 0x40; | ||
| *(uint64_t*)0x20000028 = 0; | ||
| *(uint32_t*)0x20000030 = 0; | ||
| *(uint16_t*)0x20000034 = 0; | ||
| *(uint16_t*)0x20000036 = 0x38; | ||
| *(uint16_t*)0x20000038 = 0; | ||
| *(uint16_t*)0x2000003a = 0; | ||
| *(uint16_t*)0x2000003c = 0; | ||
| *(uint16_t*)0x2000003e = 0; | ||
| *(uint32_t*)0x20000040 = 0; | ||
| *(uint32_t*)0x20000044 = 0; | ||
| *(uint64_t*)0x20000048 = 0; | ||
| *(uint64_t*)0x20000050 = 0; | ||
| *(uint64_t*)0x20000058 = 0; | ||
| *(uint64_t*)0x20000060 = 0; | ||
| *(uint64_t*)0x20000068 = 0; | ||
| *(uint64_t*)0x20000070 = 0; | ||
| syscall(__NR_write, r[1], 0x20000000ul, 0x78ul); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,191 @@ | ||
| // general protection fault in pagemap_pmd_range | ||
| // https://syzkaller.appspot.com/bug?id=024b4f3d076f4b520b80b7affdb89a4c7c1797ff | ||
| // status:invalid | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <endian.h> | ||
| #include <fcntl.h> | ||
| #include <net/if.h> | ||
| #include <netinet/in.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.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 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_procfs(volatile long a0, volatile long a1) | ||
| { | ||
| char buf[128]; | ||
| memset(buf, 0, sizeof(buf)); | ||
| if (a0 == 0) { | ||
| snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1); | ||
| } else if (a0 == -1) { | ||
| snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1); | ||
| } else { | ||
| snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1); | ||
| } | ||
| int fd = open(buf, O_RDWR); | ||
| if (fd == -1) | ||
| fd = open(buf, O_RDONLY); | ||
| return fd; | ||
| } | ||
|
|
||
| uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); | ||
| intptr_t res = 0; | ||
| res = syscall(__NR_socket, 0xa, 2, 0); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| memcpy((void*)0x20000440, "pagemap\000", 8); | ||
| res = syz_open_procfs(0, 0x20000440); | ||
| if (res != -1) | ||
| r[1] = res; | ||
| syscall(__NR_sendfile, r[0], r[1], 0, 0x100000206201); | ||
| syscall(__NR_connect, -1, 0, 0); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,347 @@ | ||
| // general protection fault in virtio_transport_release | ||
| // https://syzkaller.appspot.com/bug?id=03d4470b64b2524f9dfdc814940972203d04d398 | ||
| // status:fixed | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <endian.h> | ||
| #include <errno.h> | ||
| #include <fcntl.h> | ||
| #include <net/if.h> | ||
| #include <netinet/in.h> | ||
| #include <stdarg.h> | ||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.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 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[1024]; | ||
| }; | ||
|
|
||
| static struct nlmsg nlmsg; | ||
|
|
||
| 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; | ||
| memcpy(attr + 1, data, size); | ||
| nlmsg->pos += NLMSG_ALIGN(attr->nla_len); | ||
| } | ||
|
|
||
| static int netlink_send_ext(struct nlmsg* nlmsg, 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 (hdr->nlmsg_type == NLMSG_DONE) { | ||
| *reply_len = 0; | ||
| return 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(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| return netlink_send_ext(nlmsg, sock, 0, NULL); | ||
| } | ||
|
|
||
| static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset, | ||
| unsigned int total_len) | ||
| { | ||
| struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset); | ||
| if (offset == total_len || offset + hdr->nlmsg_len > total_len) | ||
| return -1; | ||
| return hdr->nlmsg_len; | ||
| } | ||
|
|
||
| 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); | ||
| (void)err; | ||
| } | ||
|
|
||
| const int kInitNetNsFd = 239; | ||
|
|
||
| #define DEVLINK_FAMILY_NAME "devlink" | ||
|
|
||
| #define DEVLINK_CMD_PORT_GET 5 | ||
| #define DEVLINK_CMD_RELOAD 37 | ||
| #define DEVLINK_ATTR_BUS_NAME 1 | ||
| #define DEVLINK_ATTR_DEV_NAME 2 | ||
| #define DEVLINK_ATTR_NETDEV_NAME 7 | ||
| #define DEVLINK_ATTR_NETNS_FD 137 | ||
|
|
||
| static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| struct nlattr* attr; | ||
| int err, n; | ||
| uint16_t id = 0; | ||
| 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, DEVLINK_FAMILY_NAME, | ||
| strlen(DEVLINK_FAMILY_NAME) + 1); | ||
| err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n); | ||
| if (err) { | ||
| return -1; | ||
| } | ||
| 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) { | ||
| return -1; | ||
| } | ||
| recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */ | ||
| return id; | ||
| } | ||
|
|
||
| static void netlink_devlink_netns_move(const char* bus_name, | ||
| const char* dev_name, int netns_fd) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int sock; | ||
| int id; | ||
| sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_RELOAD; | ||
| netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd)); | ||
| netlink_send(&nlmsg, sock); | ||
| error: | ||
| close(sock); | ||
| } | ||
|
|
||
| static struct nlmsg nlmsg2; | ||
|
|
||
| static void initialize_devlink_ports(const char* bus_name, const char* dev_name, | ||
| const char* netdev_prefix) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int len, total_len, id, err, offset; | ||
| uint16_t netdev_index; | ||
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
| if (rtsock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_PORT_GET; | ||
| netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| err = netlink_send_ext(&nlmsg, sock, id, &total_len); | ||
| if (err) { | ||
| goto error; | ||
| } | ||
| offset = 0; | ||
| netdev_index = 0; | ||
| while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) { | ||
| struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + | ||
| NLMSG_ALIGN(sizeof(genlhdr))); | ||
| for (; (char*)attr < nlmsg.buf + offset + len; | ||
| attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { | ||
| if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) { | ||
| char* port_name; | ||
| char netdev_name[IFNAMSIZ]; | ||
| port_name = (char*)(attr + 1); | ||
| snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, | ||
| netdev_index); | ||
| netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, | ||
| netdev_name); | ||
| break; | ||
| } | ||
| } | ||
| offset += len; | ||
| netdev_index++; | ||
| } | ||
| error: | ||
| close(rtsock); | ||
| 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); | ||
| initialize_devlink_ports("pci", "0000:00:10.0", "netpci"); | ||
| } | ||
|
|
||
| static int inject_fault(int nth) | ||
| { | ||
| int fd; | ||
| fd = open("/proc/thread-self/fail-nth", O_RDWR); | ||
| if (fd == -1) | ||
| exit(1); | ||
| char buf[16]; | ||
| sprintf(buf, "%d", nth + 1); | ||
| if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) | ||
| exit(1); | ||
| return fd; | ||
| } | ||
|
|
||
| static void setup_fault() | ||
| { | ||
| static struct { | ||
| const char* file; | ||
| const char* val; | ||
| bool fatal; | ||
| } files[] = { | ||
| {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true}, | ||
| {"/sys/kernel/debug/fail_futex/ignore-private", "N", false}, | ||
| {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false}, | ||
| {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false}, | ||
| {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false}, | ||
| }; | ||
| unsigned i; | ||
| for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) { | ||
| if (!write_file(files[i].file, files[i].val)) { | ||
| if (files[i].fatal) | ||
| exit(1); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| setup_fault(); | ||
| intptr_t res = 0; | ||
| res = syscall(__NR_socket, 2ul, 2ul, 0x88ul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| syscall(__NR_ioctl, r[0], 0x1000008912ul, 0ul); | ||
| res = syscall(__NR_socket, 0x28ul, 1ul, 0ul); | ||
| if (res != -1) | ||
| r[1] = res; | ||
| *(uint16_t*)0x200000c0 = 0x28; | ||
| *(uint16_t*)0x200000c2 = 0; | ||
| *(uint32_t*)0x200000c4 = 0; | ||
| *(uint32_t*)0x200000c8 = -1; | ||
| *(uint32_t*)0x200000cc = 0; | ||
| inject_fault(0); | ||
| syscall(__NR_connect, r[1], 0x200000c0ul, 0x10ul); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,374 @@ | ||
| // BUG: unable to handle kernel paging request in do_con_trol | ||
| // https://syzkaller.appspot.com/bug?id=04775771a119c1ba4974a07c365475ada756a40d | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <endian.h> | ||
| #include <fcntl.h> | ||
| #include <net/if.h> | ||
| #include <netinet/in.h> | ||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.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> | ||
|
|
||
| struct nlmsg { | ||
| char* pos; | ||
| int nesting; | ||
| struct nlattr* nested[8]; | ||
| char buf[1024]; | ||
| }; | ||
|
|
||
| static struct nlmsg nlmsg; | ||
|
|
||
| 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; | ||
| memcpy(attr + 1, data, size); | ||
| nlmsg->pos += NLMSG_ALIGN(attr->nla_len); | ||
| } | ||
|
|
||
| static int netlink_send_ext(struct nlmsg* nlmsg, 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 (hdr->nlmsg_type == NLMSG_DONE) { | ||
| *reply_len = 0; | ||
| return 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(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| return netlink_send_ext(nlmsg, sock, 0, NULL); | ||
| } | ||
|
|
||
| static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset, | ||
| unsigned int total_len) | ||
| { | ||
| struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset); | ||
| if (offset == total_len || offset + hdr->nlmsg_len > total_len) | ||
| return -1; | ||
| return hdr->nlmsg_len; | ||
| } | ||
|
|
||
| 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); | ||
| (void)err; | ||
| } | ||
|
|
||
| const int kInitNetNsFd = 239; | ||
|
|
||
| #define DEVLINK_FAMILY_NAME "devlink" | ||
|
|
||
| #define DEVLINK_CMD_PORT_GET 5 | ||
| #define DEVLINK_CMD_RELOAD 37 | ||
| #define DEVLINK_ATTR_BUS_NAME 1 | ||
| #define DEVLINK_ATTR_DEV_NAME 2 | ||
| #define DEVLINK_ATTR_NETDEV_NAME 7 | ||
| #define DEVLINK_ATTR_NETNS_FD 138 | ||
|
|
||
| static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| struct nlattr* attr; | ||
| int err, n; | ||
| uint16_t id = 0; | ||
| 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, DEVLINK_FAMILY_NAME, | ||
| strlen(DEVLINK_FAMILY_NAME) + 1); | ||
| err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n); | ||
| if (err) { | ||
| return -1; | ||
| } | ||
| 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) { | ||
| return -1; | ||
| } | ||
| recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */ | ||
| return id; | ||
| } | ||
|
|
||
| static void netlink_devlink_netns_move(const char* bus_name, | ||
| const char* dev_name, int netns_fd) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int sock; | ||
| int id, err; | ||
| sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_RELOAD; | ||
| netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd)); | ||
| err = netlink_send(&nlmsg, sock); | ||
| if (err) { | ||
| } | ||
| error: | ||
| close(sock); | ||
| } | ||
|
|
||
| static struct nlmsg nlmsg2; | ||
|
|
||
| static void initialize_devlink_ports(const char* bus_name, const char* dev_name, | ||
| const char* netdev_prefix) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int len, total_len, id, err, offset; | ||
| uint16_t netdev_index; | ||
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
| if (rtsock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_PORT_GET; | ||
| netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| err = netlink_send_ext(&nlmsg, sock, id, &total_len); | ||
| if (err) { | ||
| goto error; | ||
| } | ||
| offset = 0; | ||
| netdev_index = 0; | ||
| while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) { | ||
| struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + | ||
| NLMSG_ALIGN(sizeof(genlhdr))); | ||
| for (; (char*)attr < nlmsg.buf + offset + len; | ||
| attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { | ||
| if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) { | ||
| char* port_name; | ||
| char netdev_name[IFNAMSIZ]; | ||
| port_name = (char*)(attr + 1); | ||
| snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, | ||
| netdev_index); | ||
| netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, | ||
| netdev_name); | ||
| break; | ||
| } | ||
| } | ||
| offset += len; | ||
| netdev_index++; | ||
| } | ||
| error: | ||
| close(rtsock); | ||
| 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); | ||
| initialize_devlink_ports("pci", "0000:00:10.0", "netpci"); | ||
| } | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
|
|
||
| uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| intptr_t res = 0; | ||
| memcpy((void*)0x20000100, "/dev/fb0\000", 9); | ||
| res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000100ul, 0ul, 0ul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| *(uint32_t*)0x20000140 = 0; | ||
| *(uint32_t*)0x20000144 = 0; | ||
| *(uint32_t*)0x20000148 = 0; | ||
| *(uint32_t*)0x2000014c = 0; | ||
| *(uint32_t*)0x20000150 = 0; | ||
| *(uint32_t*)0x20000154 = 0; | ||
| *(uint32_t*)0x20000158 = 8; | ||
| *(uint32_t*)0x2000015c = 0; | ||
| *(uint32_t*)0x20000160 = 0; | ||
| *(uint32_t*)0x20000164 = 0; | ||
| *(uint32_t*)0x20000168 = 0; | ||
| *(uint32_t*)0x2000016c = 0; | ||
| *(uint32_t*)0x20000170 = 0; | ||
| *(uint32_t*)0x20000174 = 0; | ||
| *(uint32_t*)0x20000178 = 0; | ||
| *(uint32_t*)0x2000017c = 0; | ||
| *(uint32_t*)0x20000180 = 0; | ||
| *(uint32_t*)0x20000184 = 0; | ||
| *(uint32_t*)0x20000188 = 0; | ||
| *(uint32_t*)0x2000018c = 0; | ||
| *(uint32_t*)0x20000190 = 0; | ||
| *(uint32_t*)0x20000194 = 0; | ||
| *(uint32_t*)0x20000198 = 0; | ||
| *(uint32_t*)0x2000019c = 0; | ||
| *(uint32_t*)0x200001a0 = 0; | ||
| *(uint32_t*)0x200001a4 = 0; | ||
| *(uint32_t*)0x200001a8 = 0; | ||
| *(uint32_t*)0x200001ac = 0; | ||
| *(uint32_t*)0x200001b0 = 0; | ||
| *(uint32_t*)0x200001b4 = 0; | ||
| *(uint32_t*)0x200001b8 = 0; | ||
| *(uint32_t*)0x200001bc = 0; | ||
| *(uint32_t*)0x200001c0 = 0; | ||
| *(uint32_t*)0x200001c4 = 3; | ||
| *(uint32_t*)0x200001c8 = 0; | ||
| *(uint32_t*)0x200001cc = 0; | ||
| *(uint32_t*)0x200001d0 = 0; | ||
| *(uint32_t*)0x200001d4 = 0; | ||
| *(uint32_t*)0x200001d8 = 0; | ||
| *(uint32_t*)0x200001dc = 0; | ||
| syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000140ul); | ||
| res = syz_open_dev(0xc, 4, 0x14); | ||
| if (res != -1) | ||
| r[1] = res; | ||
| *(uint8_t*)0x20000200 = 0x1b; | ||
| *(uint8_t*)0x20000201 = 0x5b; | ||
| *(uint8_t*)0x20000202 = 0x4b; | ||
| *(uint8_t*)0x20000203 = 0x9b; | ||
| *(uint8_t*)0x20000204 = 0; | ||
| *(uint8_t*)0x20000205 = 0; | ||
| *(uint8_t*)0x20000206 = 0; | ||
| *(uint8_t*)0x20000207 = 0; | ||
| *(uint64_t*)0x20000208 = 0; | ||
| *(uint16_t*)0x20000210 = 0; | ||
| *(uint16_t*)0x20000212 = 0; | ||
| *(uint32_t*)0x20000214 = 0; | ||
| *(uint64_t*)0x20000218 = 0; | ||
| *(uint64_t*)0x20000220 = 0x40; | ||
| *(uint64_t*)0x20000228 = 0; | ||
| *(uint32_t*)0x20000230 = 0; | ||
| *(uint16_t*)0x20000234 = 0; | ||
| *(uint16_t*)0x20000236 = 0x38; | ||
| *(uint16_t*)0x20000238 = 0; | ||
| *(uint16_t*)0x2000023a = 0; | ||
| *(uint16_t*)0x2000023c = 0; | ||
| *(uint16_t*)0x2000023e = 0; | ||
| *(uint32_t*)0x20000240 = 0; | ||
| *(uint32_t*)0x20000244 = 0; | ||
| *(uint64_t*)0x20000248 = 0; | ||
| *(uint64_t*)0x20000250 = 0; | ||
| *(uint64_t*)0x20000258 = 0; | ||
| *(uint64_t*)0x20000260 = 0; | ||
| *(uint64_t*)0x20000268 = 0; | ||
| *(uint64_t*)0x20000270 = 0; | ||
| syscall(__NR_write, r[1], 0x20000200ul, 0x78ul); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,111 @@ | ||
| // general protection fault in nft_chain_parse_hook | ||
| // https://syzkaller.appspot.com/bug?id=059f48dafc729cacafe8430d24a70920d4134c05 | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <endian.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.h> | ||
| #include <unistd.h> | ||
|
|
||
| #define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off)) | ||
| #define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \ | ||
| *(type*)(addr) = \ | ||
| htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \ | ||
| (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len)))) | ||
|
|
||
| uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| intptr_t res = 0; | ||
| res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| *(uint64_t*)0x20000280 = 0; | ||
| *(uint32_t*)0x20000288 = 8; | ||
| *(uint64_t*)0x20000290 = 0x20000240; | ||
| *(uint64_t*)0x20000240 = 0x20000100; | ||
| memcpy((void*)0x20000100, | ||
| "\x14\x00\x00\x00\x10\x00\x00\x00\x1e\x6c\x00\x00\x00\x08\x00\x00\x00" | ||
| "\x00\x00\x0a\x20\x00\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x00\x00\x00" | ||
| "\x00\x00\x00\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00" | ||
| "\x00\x38\x00\x00\x00\x12\x0a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" | ||
| "\x00\x00\x00\x08\x04\x00\x04\x80\x09\x00\x02\x00\x00\x39\x7d\x00\x00" | ||
| "\x00\x00\x00\x09\x00\x01\x00\x73\x79\x7a\x30\x00\x00\x00\x00\x08\x00" | ||
| "\x03\x40\x00\x00\x00\x01\x14\x00\x00\x00\x11\x00\xdf\x00\x00\x00\x00" | ||
| "\x00\x00\x00\x00\x00\x00\x00\x00\x0a", | ||
| 128); | ||
| *(uint64_t*)0x20000248 = 0x80; | ||
| *(uint64_t*)0x20000298 = 1; | ||
| *(uint64_t*)0x200002a0 = 0; | ||
| *(uint64_t*)0x200002a8 = 0; | ||
| *(uint32_t*)0x200002b0 = 0; | ||
| syscall(__NR_sendmsg, r[0], 0x20000280ul, 0ul); | ||
| res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul); | ||
| if (res != -1) | ||
| r[1] = res; | ||
| *(uint64_t*)0x2000d400 = 0; | ||
| *(uint32_t*)0x2000d408 = 0; | ||
| *(uint64_t*)0x2000d410 = 0x2000d3c0; | ||
| *(uint64_t*)0x2000d3c0 = 0x20009e80; | ||
| *(uint32_t*)0x20009e80 = 0x14; | ||
| *(uint16_t*)0x20009e84 = 0x10; | ||
| *(uint16_t*)0x20009e86 = 1; | ||
| *(uint32_t*)0x20009e88 = 0; | ||
| *(uint32_t*)0x20009e8c = 0; | ||
| *(uint8_t*)0x20009e90 = 0; | ||
| *(uint8_t*)0x20009e91 = 0; | ||
| *(uint16_t*)0x20009e92 = htobe16(0xa); | ||
| *(uint32_t*)0x20009e94 = 0x40; | ||
| *(uint8_t*)0x20009e98 = 3; | ||
| *(uint8_t*)0x20009e99 = 0xa; | ||
| *(uint16_t*)0x20009e9a = 0x401; | ||
| *(uint32_t*)0x20009e9c = 0; | ||
| *(uint32_t*)0x20009ea0 = 0; | ||
| *(uint8_t*)0x20009ea4 = 0; | ||
| *(uint8_t*)0x20009ea5 = 0; | ||
| *(uint16_t*)0x20009ea6 = htobe16(0); | ||
| *(uint16_t*)0x20009ea8 = 9; | ||
| *(uint16_t*)0x20009eaa = 3; | ||
| memcpy((void*)0x20009eac, "syz2\000", 5); | ||
| *(uint16_t*)0x20009eb4 = 9; | ||
| *(uint16_t*)0x20009eb6 = 1; | ||
| memcpy((void*)0x20009eb8, "syz0\000", 5); | ||
| *(uint16_t*)0x20009ec0 = 0x14; | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ec2, 4, 0, 14); | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ec3, 0, 6, 1); | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ec3, 1, 7, 1); | ||
| *(uint16_t*)0x20009ec4 = 8; | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ec6, 1, 0, 14); | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ec7, 1, 6, 1); | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ec7, 0, 7, 1); | ||
| *(uint32_t*)0x20009ec8 = htobe32(0); | ||
| *(uint16_t*)0x20009ecc = 8; | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ece, 2, 0, 14); | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ecf, 1, 6, 1); | ||
| STORE_BY_BITMASK(uint16_t, , 0x20009ecf, 0, 7, 1); | ||
| *(uint32_t*)0x20009ed0 = htobe32(0); | ||
| *(uint32_t*)0x20009ed4 = 0x14; | ||
| *(uint16_t*)0x20009ed8 = 0x11; | ||
| *(uint16_t*)0x20009eda = 1; | ||
| *(uint32_t*)0x20009edc = 0; | ||
| *(uint32_t*)0x20009ee0 = 0; | ||
| *(uint8_t*)0x20009ee4 = 0; | ||
| *(uint8_t*)0x20009ee5 = 0; | ||
| *(uint16_t*)0x20009ee6 = htobe16(0xa); | ||
| *(uint64_t*)0x2000d3c8 = 0x68; | ||
| *(uint64_t*)0x2000d418 = 1; | ||
| *(uint64_t*)0x2000d420 = 0; | ||
| *(uint64_t*)0x2000d428 = 0; | ||
| *(uint32_t*)0x2000d430 = 0x4000000; | ||
| syscall(__NR_sendmsg, r[1], 0x2000d400ul, 0x4000000ul); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,33 @@ | ||
| // WARNING: refcount bug in put_watch | ||
| // https://syzkaller.appspot.com/bug?id=09c941f946e4a934981811f9f53a015356d4d281 | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <endian.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.h> | ||
| #include <unistd.h> | ||
|
|
||
| #ifndef __NR_watch_devices | ||
| #define __NR_watch_devices 436 | ||
| #endif | ||
|
|
||
| uint64_t r[1] = {0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| intptr_t res = 0; | ||
| memcpy((void*)0x20000000, "/dev/watch_queue\000", 17); | ||
| res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000000ul, 0ul, 0ul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| syscall(__NR_watch_devices, r[0], 0x42ul, 0ul); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,194 @@ | ||
| // KMSAN: use-after-free in copyout | ||
| // https://syzkaller.appspot.com/bug?id=0b5da7af1edc95677e6a4eb483c0eefcd4db4c55 | ||
| // status:fixed | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <dirent.h> | ||
| #include <endian.h> | ||
| #include <errno.h> | ||
| #include <fcntl.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> | ||
|
|
||
| unsigned long long procid; | ||
|
|
||
| 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 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, 0x0, 0x0}; | ||
|
|
||
| void execute_one(void) | ||
| { | ||
| intptr_t res = 0; | ||
| memcpy((void*)0x200000c0, "/dev/ptmx\000", 10); | ||
| res = syscall(__NR_openat, 0xffffffffffffff9c, 0x200000c0, 0, 0); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| *(uint32_t*)0x20000040 = 0xf; | ||
| syscall(__NR_ioctl, r[0], 0x5423, 0x20000040); | ||
| syscall(__NR_ioctl, r[0], 0x400455c8, 1); | ||
| memcpy((void*)0x20000040, "user\000", 5); | ||
| memcpy((void*)0x20000000, "syz", 3); | ||
| *(uint8_t*)0x20000003 = 0; | ||
| *(uint8_t*)0x20000004 = 0; | ||
| memcpy((void*)0x200002c0, | ||
| "\x58\x5c\xcb\xe4\xed\x83\xb8\x36\xc1\xa6\x47\x49\x14\xdc\x55\xe7\x22" | ||
| "\x06\x29\x7b\x68\x95\xb6\x61\x47\xb3\xc7\x21\x8a\x91\x69\xa8\x5e\xa0" | ||
| "\xbd\xc9\xe1\x58\x7a\x05\x00\x00\x00\x00\x00\x00\x00\x42\xe3\x30\x89" | ||
| "\x75\x4c\x81\x07\xc3\xcd\x39\x23\xdd\x4a\x71\xc2\xff\x06\x00\x7b\x6b" | ||
| "\x48\x16\x12\x2d\x25\x50\x82\x9e\xaa\x94\x35\xc9\x99\x26\x02\x2b\x87" | ||
| "\x53\xa1\x88\x74\x8c\x56\x9f\x43\x5f\xb3\xba\xe9\x6e\xfb\x74\xb5\x0e" | ||
| "\xc9\x3c\x15\x2f\x5e\x8e\x19\x8a\x29\xe5\xc0\xd0\xc6\x00\x00\xce\x06" | ||
| "\x37\xce\x00\x00\xb4\xec\x24\xc5\x3d\x3d\x66\x1f\xf5\xff\x70\xe4\x88" | ||
| "\x84\xca\x00\x00\x18\xce\xa7\x1f\xcf\xac\xf4\x0d\x32\xe4\xb5\x8a\x8d" | ||
| "\x27\x25\x56\x1f\x61\x10\xfd\x7b\x06\xf9\x0b\x52\x74\xcc\x5c\x1e\x29" | ||
| "\x8a\x16\x32\x4f\xe2\x7d\xa2\xa9\xd5\xba\x9f\xf3\xc0\x09\xd3\x08\xbd" | ||
| "\x73\xf4\x77\x25\x39", | ||
| 192); | ||
| res = syscall(__NR_add_key, 0x20000040, 0x20000000, 0x200002c0, 0xc0, | ||
| 0xfffffffe); | ||
| if (res != -1) | ||
| r[1] = res; | ||
| memcpy((void*)0x20000200, "user\000", 5); | ||
| memcpy((void*)0x200005c0, "syz", 3); | ||
| *(uint8_t*)0x200005c3 = 0; | ||
| *(uint8_t*)0x200005c4 = 0; | ||
| res = syscall(__NR_add_key, 0x20000200, 0x200005c0, 0x200000c0, 0x9a, | ||
| 0xfffffffd); | ||
| if (res != -1) | ||
| r[2] = res; | ||
| *(uint32_t*)0x200000c0 = r[2]; | ||
| *(uint32_t*)0x200000c4 = r[1]; | ||
| *(uint32_t*)0x200000c8 = r[2]; | ||
| syscall(__NR_keyctl, 0x17, 0x200000c0, 0x9999999999999999, 0xf9ffffff, 0); | ||
| } | ||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); | ||
| for (procid = 0; procid < 6; procid++) { | ||
| if (fork() == 0) { | ||
| loop(); | ||
| } | ||
| } | ||
| sleep(1000000); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,182 @@ | ||
| // KASAN: use-after-free Write in release_tty | ||
| // https://syzkaller.appspot.com/bug?id=0bd948d2fcdbd3ba337dbd53fdca59b4afe9787d | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <dirent.h> | ||
| #include <endian.h> | ||
| #include <errno.h> | ||
| #include <fcntl.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> | ||
|
|
||
| unsigned long long procid; | ||
|
|
||
| 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 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); | ||
| 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[2] = {0xffffffffffffffff, 0xffffffffffffffff}; | ||
|
|
||
| void execute_one(void) | ||
| { | ||
| intptr_t res = 0; | ||
| syz_open_dev(0xc, 4, 0x15 + procid * 2); | ||
| res = syz_open_dev(0xc, 4, 1); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| res = syscall(__NR_pipe, 0x20000000ul); | ||
| if (res != -1) | ||
| r[1] = *(uint32_t*)0x20000000; | ||
| syscall(__NR_dup2, r[0], r[1]); | ||
| syscall(__NR_ioctl, r[1], 0x5608ul, 0); | ||
| } | ||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| for (procid = 0; procid < 6; procid++) { | ||
| if (fork() == 0) { | ||
| loop(); | ||
| } | ||
| } | ||
| sleep(1000000); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,158 @@ | ||
| // WARNING: bad unlock balance in rcu_core | ||
| // https://syzkaller.appspot.com/bug?id=0d5bdaf028e4283ad7404609d17e5077f48ff26d | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <dirent.h> | ||
| #include <endian.h> | ||
| #include <errno.h> | ||
| #include <fcntl.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> | ||
|
|
||
| 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 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; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void execute_one(void) | ||
| { | ||
| memcpy((void*)0x20000380, "/dev/infiniband/rdma_cm\000", 24); | ||
| syscall(__NR_openat, 0xffffffffffffff9c, 0x20000380, 2, 0); | ||
| memcpy((void*)0x20000040, "./file0\000", 8); | ||
| syscall(__NR_mkdir, 0x20000040, 0); | ||
| memcpy((void*)0x200004c0, | ||
| "\x2f\x64\x65\x76\x2f\x6e\x75\x6c\x6c\x62\x30\x00\x46\x72\x5c\x60\x12" | ||
| "\xee\x37\x5d\x54\xe0\xb2\x59\x6d\xd0\x78\x30\xb9\x14\xd0\x2e\xb7\x5b" | ||
| "\xfe\x1b\xdf\xf9\x7a\xc2\x75\xcb\x63\x88\x4e\xba\x73\x99\xf1\x21\x7a" | ||
| "\x2d\x24\x98\xcd\x09\x18\xff\xb5\x46\xf2\x72\xbe\x7d\xb7\xa0\xde\x21" | ||
| "\x2a\xb5\x88\x95\xd1\xae\x81\x37\xf3\x05\xe0\xa3\x3d\xa9\x57\xbd\x36" | ||
| "\xe5\x5b\x1f\x06\x22\x8b\xae\x6f\x8f\x51\x56\x0a\x30\x74\x14\x7a\x7b", | ||
| 102); | ||
| memcpy((void*)0x20000280, "./file0\000", 8); | ||
| memcpy((void*)0x20000140, "ntfs\000", 5); | ||
| syscall(__NR_mount, 0x200004c0, 0x20000280, 0x20000140, 0, 0); | ||
| } | ||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); | ||
| loop(); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,319 @@ | ||
| // KASAN: global-out-of-bounds Read in vga16fb_imageblit | ||
| // https://syzkaller.appspot.com/bug?id=0d7a0da1557dcd1989e00cb3692b26d4173b4132 | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <endian.h> | ||
| #include <fcntl.h> | ||
| #include <net/if.h> | ||
| #include <netinet/in.h> | ||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.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> | ||
|
|
||
| struct nlmsg { | ||
| char* pos; | ||
| int nesting; | ||
| struct nlattr* nested[8]; | ||
| char buf[1024]; | ||
| }; | ||
|
|
||
| static struct nlmsg nlmsg; | ||
|
|
||
| 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; | ||
| memcpy(attr + 1, data, size); | ||
| nlmsg->pos += NLMSG_ALIGN(attr->nla_len); | ||
| } | ||
|
|
||
| static int netlink_send_ext(struct nlmsg* nlmsg, 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 (hdr->nlmsg_type == NLMSG_DONE) { | ||
| *reply_len = 0; | ||
| return 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(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| return netlink_send_ext(nlmsg, sock, 0, NULL); | ||
| } | ||
|
|
||
| static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset, | ||
| unsigned int total_len) | ||
| { | ||
| struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset); | ||
| if (offset == total_len || offset + hdr->nlmsg_len > total_len) | ||
| return -1; | ||
| return hdr->nlmsg_len; | ||
| } | ||
|
|
||
| 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); | ||
| (void)err; | ||
| } | ||
|
|
||
| const int kInitNetNsFd = 239; | ||
|
|
||
| #define DEVLINK_FAMILY_NAME "devlink" | ||
|
|
||
| #define DEVLINK_CMD_PORT_GET 5 | ||
| #define DEVLINK_CMD_RELOAD 37 | ||
| #define DEVLINK_ATTR_BUS_NAME 1 | ||
| #define DEVLINK_ATTR_DEV_NAME 2 | ||
| #define DEVLINK_ATTR_NETDEV_NAME 7 | ||
| #define DEVLINK_ATTR_NETNS_FD 138 | ||
|
|
||
| static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| struct nlattr* attr; | ||
| int err, n; | ||
| uint16_t id = 0; | ||
| 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, DEVLINK_FAMILY_NAME, | ||
| strlen(DEVLINK_FAMILY_NAME) + 1); | ||
| err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n); | ||
| if (err) { | ||
| return -1; | ||
| } | ||
| 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) { | ||
| return -1; | ||
| } | ||
| recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */ | ||
| return id; | ||
| } | ||
|
|
||
| static void netlink_devlink_netns_move(const char* bus_name, | ||
| const char* dev_name, int netns_fd) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int sock; | ||
| int id, err; | ||
| sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_RELOAD; | ||
| netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd)); | ||
| err = netlink_send(&nlmsg, sock); | ||
| if (err) { | ||
| } | ||
| error: | ||
| close(sock); | ||
| } | ||
|
|
||
| static struct nlmsg nlmsg2; | ||
|
|
||
| static void initialize_devlink_ports(const char* bus_name, const char* dev_name, | ||
| const char* netdev_prefix) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int len, total_len, id, err, offset; | ||
| uint16_t netdev_index; | ||
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
| if (rtsock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_PORT_GET; | ||
| netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| err = netlink_send_ext(&nlmsg, sock, id, &total_len); | ||
| if (err) { | ||
| goto error; | ||
| } | ||
| offset = 0; | ||
| netdev_index = 0; | ||
| while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) { | ||
| struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + | ||
| NLMSG_ALIGN(sizeof(genlhdr))); | ||
| for (; (char*)attr < nlmsg.buf + offset + len; | ||
| attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { | ||
| if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) { | ||
| char* port_name; | ||
| char netdev_name[IFNAMSIZ]; | ||
| port_name = (char*)(attr + 1); | ||
| snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, | ||
| netdev_index); | ||
| netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, | ||
| netdev_name); | ||
| break; | ||
| } | ||
| } | ||
| offset += len; | ||
| netdev_index++; | ||
| } | ||
| error: | ||
| close(rtsock); | ||
| 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); | ||
| initialize_devlink_ports("pci", "0000:00:10.0", "netpci"); | ||
| } | ||
|
|
||
| uint64_t r[1] = {0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| intptr_t res = 0; | ||
| memcpy((void*)0x20000180, "/dev/fb0\000", 9); | ||
| res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000180ul, 0ul, 0ul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| *(uint32_t*)0x20000000 = 0; | ||
| *(uint32_t*)0x20000004 = 0; | ||
| *(uint32_t*)0x20000008 = 0; | ||
| *(uint32_t*)0x2000000c = 0; | ||
| *(uint32_t*)0x20000010 = 0; | ||
| *(uint32_t*)0x20000014 = 0; | ||
| *(uint32_t*)0x20000018 = 8; | ||
| *(uint32_t*)0x2000001c = 0; | ||
| *(uint32_t*)0x20000020 = 0; | ||
| *(uint32_t*)0x20000024 = 0; | ||
| *(uint32_t*)0x20000028 = 0; | ||
| *(uint32_t*)0x2000002c = 0; | ||
| *(uint32_t*)0x20000030 = 0; | ||
| *(uint32_t*)0x20000034 = 0; | ||
| *(uint32_t*)0x20000038 = 0; | ||
| *(uint32_t*)0x2000003c = 0; | ||
| *(uint32_t*)0x20000040 = 0; | ||
| *(uint32_t*)0x20000044 = 0; | ||
| *(uint32_t*)0x20000048 = 0; | ||
| *(uint32_t*)0x2000004c = 0; | ||
| *(uint32_t*)0x20000050 = 2; | ||
| *(uint32_t*)0x20000054 = 0; | ||
| *(uint32_t*)0x20000058 = 0; | ||
| *(uint32_t*)0x2000005c = 0; | ||
| *(uint32_t*)0x20000060 = 0; | ||
| *(uint32_t*)0x20000064 = 0; | ||
| *(uint32_t*)0x20000068 = 0; | ||
| *(uint32_t*)0x2000006c = 0; | ||
| *(uint32_t*)0x20000070 = 8; | ||
| *(uint32_t*)0x20000074 = 0; | ||
| *(uint32_t*)0x20000078 = 0; | ||
| *(uint32_t*)0x2000007c = 0; | ||
| *(uint32_t*)0x20000080 = 0; | ||
| *(uint32_t*)0x20000084 = 0; | ||
| *(uint32_t*)0x20000088 = 0; | ||
| *(uint32_t*)0x2000008c = 0; | ||
| *(uint32_t*)0x20000090 = 0; | ||
| *(uint32_t*)0x20000094 = 0; | ||
| *(uint32_t*)0x20000098 = 0; | ||
| *(uint32_t*)0x2000009c = 0; | ||
| syscall(__NR_ioctl, r[0], 0x4601ul, 0x20000000ul); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,284 @@ | ||
| // BUG: unable to handle kernel paging request in ion_heap_clear_pages | ||
| // https://syzkaller.appspot.com/bug?id=0dd28d46dec9381ed64f55ee25269fe781439d24 | ||
| // status:open | ||
| // autogenerated by syzkaller (https://github.com/google/syzkaller) | ||
|
|
||
| #define _GNU_SOURCE | ||
|
|
||
| #include <arpa/inet.h> | ||
| #include <endian.h> | ||
| #include <fcntl.h> | ||
| #include <net/if.h> | ||
| #include <netinet/in.h> | ||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <sys/syscall.h> | ||
| #include <sys/types.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> | ||
|
|
||
| struct nlmsg { | ||
| char* pos; | ||
| int nesting; | ||
| struct nlattr* nested[8]; | ||
| char buf[1024]; | ||
| }; | ||
|
|
||
| static struct nlmsg nlmsg; | ||
|
|
||
| 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; | ||
| memcpy(attr + 1, data, size); | ||
| nlmsg->pos += NLMSG_ALIGN(attr->nla_len); | ||
| } | ||
|
|
||
| static int netlink_send_ext(struct nlmsg* nlmsg, 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 (hdr->nlmsg_type == NLMSG_DONE) { | ||
| *reply_len = 0; | ||
| return 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(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| return netlink_send_ext(nlmsg, sock, 0, NULL); | ||
| } | ||
|
|
||
| static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset, | ||
| unsigned int total_len) | ||
| { | ||
| struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset); | ||
| if (offset == total_len || offset + hdr->nlmsg_len > total_len) | ||
| return -1; | ||
| return hdr->nlmsg_len; | ||
| } | ||
|
|
||
| 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); | ||
| (void)err; | ||
| } | ||
|
|
||
| const int kInitNetNsFd = 239; | ||
|
|
||
| #define DEVLINK_FAMILY_NAME "devlink" | ||
|
|
||
| #define DEVLINK_CMD_PORT_GET 5 | ||
| #define DEVLINK_CMD_RELOAD 37 | ||
| #define DEVLINK_ATTR_BUS_NAME 1 | ||
| #define DEVLINK_ATTR_DEV_NAME 2 | ||
| #define DEVLINK_ATTR_NETDEV_NAME 7 | ||
| #define DEVLINK_ATTR_NETNS_FD 138 | ||
|
|
||
| static int netlink_devlink_id_get(struct nlmsg* nlmsg, int sock) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| struct nlattr* attr; | ||
| int err, n; | ||
| uint16_t id = 0; | ||
| 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, DEVLINK_FAMILY_NAME, | ||
| strlen(DEVLINK_FAMILY_NAME) + 1); | ||
| err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n); | ||
| if (err) { | ||
| return -1; | ||
| } | ||
| 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) { | ||
| return -1; | ||
| } | ||
| recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0); /* recv ack */ | ||
| return id; | ||
| } | ||
|
|
||
| static void netlink_devlink_netns_move(const char* bus_name, | ||
| const char* dev_name, int netns_fd) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int sock; | ||
| int id, err; | ||
| sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_RELOAD; | ||
| netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_NETNS_FD, &netns_fd, sizeof(netns_fd)); | ||
| err = netlink_send(&nlmsg, sock); | ||
| if (err) { | ||
| } | ||
| error: | ||
| close(sock); | ||
| } | ||
|
|
||
| static struct nlmsg nlmsg2; | ||
|
|
||
| static void initialize_devlink_ports(const char* bus_name, const char* dev_name, | ||
| const char* netdev_prefix) | ||
| { | ||
| struct genlmsghdr genlhdr; | ||
| int len, total_len, id, err, offset; | ||
| uint16_t netdev_index; | ||
| int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); | ||
| if (sock == -1) | ||
| exit(1); | ||
| int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
| if (rtsock == -1) | ||
| exit(1); | ||
| id = netlink_devlink_id_get(&nlmsg, sock); | ||
| if (id == -1) | ||
| goto error; | ||
| memset(&genlhdr, 0, sizeof(genlhdr)); | ||
| genlhdr.cmd = DEVLINK_CMD_PORT_GET; | ||
| netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr)); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1); | ||
| netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1); | ||
| err = netlink_send_ext(&nlmsg, sock, id, &total_len); | ||
| if (err) { | ||
| goto error; | ||
| } | ||
| offset = 0; | ||
| netdev_index = 0; | ||
| while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) { | ||
| struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + | ||
| NLMSG_ALIGN(sizeof(genlhdr))); | ||
| for (; (char*)attr < nlmsg.buf + offset + len; | ||
| attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) { | ||
| if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) { | ||
| char* port_name; | ||
| char netdev_name[IFNAMSIZ]; | ||
| port_name = (char*)(attr + 1); | ||
| snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, | ||
| netdev_index); | ||
| netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, | ||
| netdev_name); | ||
| break; | ||
| } | ||
| } | ||
| offset += len; | ||
| netdev_index++; | ||
| } | ||
| error: | ||
| close(rtsock); | ||
| 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); | ||
| initialize_devlink_ports("pci", "0000:00:10.0", "netpci"); | ||
| } | ||
|
|
||
| uint64_t r[1] = {0xffffffffffffffff}; | ||
|
|
||
| int main(void) | ||
| { | ||
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); | ||
| intptr_t res = 0; | ||
| memcpy((void*)0x20000140, "/dev/ion\000", 9); | ||
| res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000140ul, 0ul, 0ul); | ||
| if (res != -1) | ||
| r[0] = res; | ||
| *(uint64_t*)0x20000040 = 0xa925; | ||
| *(uint32_t*)0x20000048 = 1; | ||
| *(uint32_t*)0x2000004c = 0; | ||
| *(uint32_t*)0x20000050 = -1; | ||
| *(uint32_t*)0x20000054 = 0; | ||
| syscall(__NR_ioctl, r[0], 0xc0184900ul, 0x20000040ul); | ||
| return 0; | ||
| } |