blob: ff5b608f9fe80e5014cd08beb767140d3e5234f1 [file] [log] [blame]
// WARNING: ODEBUG bug in rt6_release
// https://syzkaller.appspot.com/bug?id=53b9ac095099f2e4bb92d05a1fc63ca93a9910fa
// status:open
// 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 <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>
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 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 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[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff};
void execute_one(void)
{
intptr_t res = 0;
res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
if (res != -1)
r[0] = res;
*(uint64_t*)0x200001c0 = 0x20000040;
memcpy((void*)0x20000040, "\x39\x00\x00\x00\x13\x00\x03\x47\x00\xbb\x65\xe1"
"\xc3\xe4\xff\xff\x06\x00\x00\x00\x01\x00\x00\x00"
"\x45\x00\x00\x00\x25\x00\x00\x00\x19\x00\x04\x00"
"\x04\x00\x00\x00\x07\xfd\x17\xe5\xff\xff\x06\x06"
"\x04\x00\x00\x00\x00\x00\x00\x00\x00",
57);
*(uint64_t*)0x200001c8 = 0x39;
syscall(__NR_writev, r[0], 0x200001c0ul, 1ul);
res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
if (res != -1)
r[1] = res;
res = syscall(__NR_socket, 0x10ul, 3ul, 0ul);
if (res != -1)
r[2] = res;
res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
if (res != -1)
r[3] = res;
*(uint64_t*)0x200001c0 = 0;
*(uint32_t*)0x200001c8 = 0;
*(uint64_t*)0x200001d0 = 0x20000180;
*(uint64_t*)0x20000180 = 0;
*(uint64_t*)0x20000188 = 0;
*(uint64_t*)0x200001d8 = 1;
*(uint64_t*)0x200001e0 = 0;
*(uint64_t*)0x200001e8 = 0;
*(uint32_t*)0x200001f0 = 0;
syscall(__NR_sendmsg, r[3], 0x200001c0ul, 0ul);
*(uint32_t*)0x20000200 = 0x14;
res = syscall(__NR_getsockname, r[3], 0x20000100ul, 0x20000200ul);
if (res != -1)
r[4] = *(uint32_t*)0x20000104;
*(uint64_t*)0x20000040 = 0;
*(uint32_t*)0x20000048 = 0;
*(uint64_t*)0x20000050 = 0x20000240;
*(uint64_t*)0x20000240 = 0x20000340;
*(uint32_t*)0x20000340 = 0x38;
*(uint16_t*)0x20000344 = 0x10;
*(uint16_t*)0x20000346 = 0x705;
*(uint32_t*)0x20000348 = 0;
*(uint32_t*)0x2000034c = 0;
*(uint8_t*)0x20000350 = 0;
*(uint8_t*)0x20000351 = 0;
*(uint16_t*)0x20000352 = 0;
*(uint32_t*)0x20000354 = r[4];
*(uint32_t*)0x20000358 = 0;
*(uint32_t*)0x2000035c = 0;
*(uint16_t*)0x20000360 = 0x18;
*(uint16_t*)0x20000362 = 0x12;
*(uint16_t*)0x20000364 = 8;
*(uint16_t*)0x20000366 = 1;
memcpy((void*)0x20000368, "vti\000", 4);
*(uint16_t*)0x2000036c = 0xc;
*(uint16_t*)0x2000036e = 2;
*(uint16_t*)0x20000370 = 8;
*(uint16_t*)0x20000372 = 1;
*(uint32_t*)0x20000374 = r[4];
*(uint64_t*)0x20000248 = 0x38;
*(uint64_t*)0x20000058 = 1;
*(uint64_t*)0x20000060 = 0;
*(uint64_t*)0x20000068 = 0;
*(uint32_t*)0x20000070 = 0;
syscall(__NR_sendmsg, r[2], 0x20000040ul, 0ul);
*(uint64_t*)0x200000c0 = 0;
*(uint32_t*)0x200000c8 = 0;
*(uint64_t*)0x200000d0 = 0x20000000;
*(uint64_t*)0x20000000 = 0x20001980;
memcpy((void*)0x20001980, "\x2c\x00\x00\x00\x14\x00\x01\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x0a\x00\x02\x00",
20);
*(uint32_t*)0x20001994 = r[4];
memcpy((void*)0x20001998, "\x14\x00\x02\x00\xc6\xe3\x94\x78\xde\x96\x9f\xf8"
"\x22\x2a\x75\x7a\x4a\xe2\x76\xc3\x1e\xf6\xd2\x32"
"\x4b\x9a",
26);
*(uint64_t*)0x20000008 = 0x2c;
*(uint64_t*)0x200000d8 = 1;
*(uint64_t*)0x200000e0 = 0;
*(uint64_t*)0x200000e8 = 0;
*(uint32_t*)0x200000f0 = 0;
syscall(__NR_sendmsg, r[1], 0x200000c0ul, 0ul);
}
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;
}