blob: d42fbace3b16020907c12917895234a2f41761fd [file] [log] [blame]
// kernel BUG at include/linux/scatterlist.h:LINE!
// https://syzkaller.appspot.com/bug?id=1db9cf841c8e310e224b9eba480f0bcfc0f2d69e
// 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>
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[2] = {0xffffffffffffffff, 0xffffffffffffffff};
void execute_one(void)
{
intptr_t res = 0;
res = syscall(__NR_socket, 0x26ul, 5ul, 0ul);
if (res != -1)
r[0] = res;
*(uint16_t*)0x20000140 = 0x26;
memcpy((void*)0x20000142, "aead\000\000\000\000\000\000\000\000\000\000", 14);
*(uint32_t*)0x20000150 = 0;
*(uint32_t*)0x20000154 = 0;
memcpy((void*)0x20000158, "generic-gcm-"
"aesni\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000",
64);
syscall(__NR_bind, r[0], 0x20000140ul, 0x58ul);
res = syscall(__NR_accept4, r[0], 0ul, 0ul, 0ul);
if (res != -1)
r[1] = res;
memcpy((void*)0x20c18000, "\xad\x56\xb6\xc5\x82\x0f\x05\x00\x00\x00\x32\x92"
"\xea\x54\xc7\xbe\xef\x91\x5d\x56\x4c\x90\xc2\x00",
24);
syscall(__NR_setsockopt, r[0], 0x117ul, 1ul, 0x20c18000ul, 0x18ul);
*(uint64_t*)0x20001240 = 0;
*(uint32_t*)0x20001248 = 0;
*(uint64_t*)0x20001250 = 0x20000540;
*(uint64_t*)0x20000540 = 0x20000440;
memcpy((void*)0x20000440,
"\x1a\xf0\x29\x63\xc6\xf0\xd5\x88\xbe\x90\x61\xbf\xf1\x5c\xac\xd0",
16);
*(uint64_t*)0x20000548 = 0x10;
*(uint64_t*)0x20001258 = 1;
*(uint64_t*)0x20001260 = 0;
*(uint64_t*)0x20001268 = 0;
*(uint32_t*)0x20001270 = 0;
syscall(__NR_sendmmsg, r[1], 0x20001240ul, 1ul, 0ul);
syscall(__NR_recvfrom, r[1], 0x20003240ul, 0x100000205ul, 0ul, 0ul, 0x415ul);
}
int main(void)
{
syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0);
loop();
return 0;
}