| // WARNING: refcount bug in sock_wfree |
| // https://syzkaller.appspot.com/bug?id=c3a53daa22919e0027037eff03304ba0081af58e |
| // 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 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"); |
| } |
| |
| uint64_t r[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, |
| 0xffffffffffffffff, 0x0}; |
| |
| int main(void) |
| { |
| syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); |
| intptr_t res = 0; |
| *(uint16_t*)0x20000000 = 0; |
| *(uint16_t*)0x20000002 = 7; |
| *(uint8_t*)0x20000004 = 0xaa; |
| *(uint8_t*)0x20000005 = 0xaa; |
| *(uint8_t*)0x20000006 = 0xaa; |
| *(uint8_t*)0x20000007 = 0xaa; |
| *(uint8_t*)0x20000008 = 0xaa; |
| *(uint8_t*)0x20000009 = 0; |
| *(uint8_t*)0x2000000a = 1; |
| *(uint8_t*)0x2000000b = 0x80; |
| *(uint8_t*)0x2000000c = 0xc2; |
| *(uint8_t*)0x2000000d = 0; |
| *(uint8_t*)0x2000000e = 0; |
| *(uint8_t*)0x2000000f = 0; |
| *(uint8_t*)0x20000010 = 0xaa; |
| *(uint8_t*)0x20000011 = 0xaa; |
| *(uint8_t*)0x20000012 = 0xaa; |
| *(uint8_t*)0x20000013 = 0xaa; |
| *(uint8_t*)0x20000014 = 0xaa; |
| *(uint8_t*)0x20000015 = 0; |
| *(uint8_t*)0x20000016 = 0; |
| *(uint8_t*)0x20000017 = 0; |
| *(uint8_t*)0x20000018 = 0; |
| *(uint8_t*)0x20000019 = 0; |
| *(uint8_t*)0x2000001a = 0; |
| *(uint8_t*)0x2000001b = 0; |
| *(uint8_t*)0x2000001c = 0xaa; |
| *(uint8_t*)0x2000001d = 0xaa; |
| *(uint8_t*)0x2000001e = 0xaa; |
| *(uint8_t*)0x2000001f = 0xaa; |
| *(uint8_t*)0x20000020 = 0xaa; |
| *(uint8_t*)0x20000021 = 0xbb; |
| *(uint8_t*)0x20000022 = 0xaa; |
| *(uint8_t*)0x20000023 = 0xaa; |
| *(uint8_t*)0x20000024 = 0xaa; |
| *(uint8_t*)0x20000025 = 0xaa; |
| *(uint8_t*)0x20000026 = 0xaa; |
| *(uint8_t*)0x20000027 = 0xbb; |
| *(uint8_t*)0x20000028 = 0xaa; |
| *(uint8_t*)0x20000029 = 0xaa; |
| *(uint8_t*)0x2000002a = 0xaa; |
| *(uint8_t*)0x2000002b = 0xaa; |
| *(uint8_t*)0x2000002c = 0xaa; |
| *(uint8_t*)0x2000002d = 0xbb; |
| syscall(__NR_ioctl, -1, 0x400454d1ul, 0x20000000ul); |
| res = syscall(__NR_socket, 0x10ul, 3ul, 0ul); |
| if (res != -1) |
| r[0] = res; |
| *(uint64_t*)0x20000080 = 0; |
| *(uint32_t*)0x20000088 = 0; |
| *(uint64_t*)0x20000090 = 0x20000040; |
| *(uint64_t*)0x20000040 = 0x20000000; |
| *(uint32_t*)0x20000000 = 0x30; |
| *(uint16_t*)0x20000004 = 0x10; |
| *(uint16_t*)0x20000006 = 0x801; |
| *(uint32_t*)0x20000008 = 0; |
| *(uint32_t*)0x2000000c = 0; |
| *(uint8_t*)0x20000010 = 0; |
| *(uint8_t*)0x20000011 = 0; |
| *(uint16_t*)0x20000012 = 0; |
| *(uint32_t*)0x20000014 = 0; |
| *(uint32_t*)0x20000018 = 0; |
| *(uint32_t*)0x2000001c = 0; |
| *(uint16_t*)0x20000020 = 8; |
| *(uint16_t*)0x20000022 = 0x1b; |
| *(uint32_t*)0x20000024 = 0; |
| *(uint16_t*)0x20000028 = 8; |
| *(uint16_t*)0x2000002a = 4; |
| *(uint8_t*)0x2000002c = 0; |
| *(uint64_t*)0x20000048 = 0x30; |
| *(uint64_t*)0x20000098 = 1; |
| *(uint64_t*)0x200000a0 = 0; |
| *(uint64_t*)0x200000a8 = 0; |
| *(uint32_t*)0x200000b0 = 0; |
| syscall(__NR_sendmsg, r[0], 0x20000080ul, 0ul); |
| res = syscall(__NR_socket, 2ul, 0x4000000805ul, 0); |
| if (res != -1) |
| r[1] = res; |
| res = syscall(__NR_socket, 2ul, 5ul, 0x84ul); |
| if (res != -1) |
| r[2] = res; |
| res = syscall(__NR_dup3, r[1], r[2], 0ul); |
| if (res != -1) |
| r[3] = res; |
| *(uint16_t*)0x20d6cff0 = 2; |
| *(uint16_t*)0x20d6cff2 = htobe16(0x4e20); |
| *(uint32_t*)0x20d6cff4 = htobe32(0x7f000001); |
| syscall(__NR_setsockopt, r[2], 0x84ul, 0x64ul, 0x20d6cff0ul, 0x10ul); |
| memcpy((void*)0x20fa3fff, "\t", 1); |
| *(uint16_t*)0x206f7000 = 2; |
| *(uint16_t*)0x206f7002 = htobe16(0); |
| *(uint8_t*)0x206f7004 = 0xac; |
| *(uint8_t*)0x206f7005 = 0x14; |
| *(uint8_t*)0x206f7006 = -1; |
| *(uint8_t*)0x206f7007 = 0xbb; |
| syscall(__NR_sendto, r[3], 0x20fa3ffful, 1ul, 0ul, 0x206f7000ul, 0x10ul); |
| memcpy((void*)0x203cef9f, "7", 1); |
| *(uint16_t*)0x20618000 = 2; |
| *(uint16_t*)0x20618002 = htobe16(0x4e20); |
| *(uint32_t*)0x20618004 = htobe32(0x7f000001); |
| syscall(__NR_sendto, r[2], 0x203cef9ful, 0xff46ul, 0ul, 0x20618000ul, 0x10ul); |
| *(uint32_t*)0x20a8a000 = 0xc; |
| res = syscall(__NR_getsockopt, r[2], 0x84ul, 0x1dul, 0x2025e000ul, |
| 0x20a8a000ul); |
| if (res != -1) |
| r[4] = *(uint32_t*)0x2025e008; |
| *(uint32_t*)0x2059aff8 = r[4]; |
| *(uint32_t*)0x2059affc = 0; |
| *(uint32_t*)0x2034f000 = 0x2059b000; |
| syscall(__NR_getsockopt, r[3], 0x84ul, 0x7aul, 0x2059aff8ul, 0x2034f000ul); |
| return 0; |
| } |