| // 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; |
| } |