// https://syzkaller.appspot.com/bug?id=b44aa2c301f6eaf8d39a53b59cb3b441a468d9cf // autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; res = syscall(__NR_socket, 0x10ul, 3ul, 0xcul); if (res != -1) r[0] = res; *(uint64_t*)0x20000200 = 0x20000000; *(uint16_t*)0x20000000 = 0x10; *(uint16_t*)0x20000002 = 0; *(uint32_t*)0x20000004 = 0; *(uint32_t*)0x20000008 = 0; *(uint32_t*)0x20000208 = 0xc; *(uint64_t*)0x20000210 = 0x20000040; *(uint64_t*)0x20000040 = 0x20000440; memcpy((void*)0x20000440, "\xfc\x00\x00\x00\x03\x08\x01\x00\x2d\xbd\x70\x00\xff\xdb\xdf\xd0\x03" "\x00\x00\x02\x0c\x00\x01\x00\x73\x79\x7a\x31\x00\x00\x00\x00\x08\x00" "\x03\x00\xe0\xff\xff\x06\x08\x00\x06\x00\x00\x00\x00\x00\x0c\x00\x04" "\x00\x08\x00\x05\x00\x00\x00\x80\x01\x08\x00\x03\x00\x21\x00\x03\xff" "\xa0\x00\x02\x00\x08\x00\x03\x00\x00\x01\x00\x00\x08\x00\x03\x00\x00" "\x00\x00\x00\x08\x00\x03\x00\x00\x00\x00\x00\x21\xab\x3d\x7d\x43\xca" "\xfe\xc0\x9f\x91\x99\x9e\x58\x14\x21\x21\x72\x4d\xc7\xca\x1f\xac\x72" "\x8e\x14\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x00\x14\x00\x01\x00\x08" "\x00\x01\x00\xac\x1e\x00\x01\x08\x00\x02\x00\x7f\x00\x00\x01\x14\x00" "\x01\x00\x08\x00\x01\x00\xac\x1e\x01\x01\x08\x00\x02\x00\xff\xff\xff" "\xff\x08\x00\x03\x00\x00\x04\x00\x00\x0c\x00\x02\x00\x08\x00\x01\x00" "\x3a\x00\x00\x00\x14\x00\x01\x00\x08\x00\x01\x00\xac\x1e\x01\x01\x08" "\x00\x02\x00\xe0\x00\x00\x02\x08\x1c\x06\x00\x00\x00\x00\x00\x08\x00" "\x86\x00\x00\x00\x00\x01\x08\x00\x05\x00\x00\x00\x00\x15\xeb\xf4\xac" "\xa3\x58\xd0\xe9\xf8\x14\x89\x08\xa2\x80\x50\x2a\xb7\x18\x0d\x54\x5a" "\x75\xd3\x82\xcd\x56\x52\x37\x17\xe6\x25\x76\x3b\xff\xe7\x69\x44\x66" "\xce\xa0\x75\xf9\x0d\xa3\xb2\xd1\x7a\x3a\x52\x0d\xb0\xdd\xb9\xa3\x94" "\x28\x24\x4b\x4c\x62\x6e\x12\x24\x7f\xba\xfa\xd4\x08\xaa\xdc\x5b\xf3" "\xce\x45\x73\x23\x32\xee\x95\x76\x59\xaf\x6e\xfb\x4a\x58\x36\x76\xec" "\x71\xe4\xee\x51\x6e\x68\x9d\x37\x56\x06\xd1\x17\x9f\x22\xf5\x69\xb6" "\x7c\x4b\x47\x87\x4a\x14\xca\x1b\xed\xd4\xc2\x8f\xde\x9b\x28\x96\xc9" "\x0e\xd8\xac\xaa\xcc\x50\xb1\xba\x79\xa2\x7c\xe2\xf8\x6f\x33\x56\xd9" "\xda\xb1\xec\x5a\xe7\xb7\x1c\x64\xe5\x42\xc4\x57\x85\x7f\xb2\xdd\x53" "\xc5\xe1\xfc\x9b\xde\xf0\x07\xdb\xe5\xfb\x55\xe0\x72\x3f\x4f\x44\xf0" "\x97\x1d\xf3\x24\xbf\x3e\x00\x51\x35\xf4\x4e\xc0\x1c\xf1\x19\xc7\x31" "\x40\x22\x82\x5c\xfe\xfc\xca\x63\xda\xbc\x87\xc8\x2d\xe5\xc6\x5a\x09" "\xeb\x9e\xee\xf2\xc8\xa9\xb2\x1d\x9e\xd0\x64\x61\xdc\x21\xec\xd2\xc2" "\x15\x70\x53\x9e\x60\x20\x75\x68\x02\xdd\x0f\x04\x61\xb4\xcf\x7d\xdb", 493); *(uint64_t*)0x20000048 = 0xfc; *(uint64_t*)0x20000218 = 1; *(uint64_t*)0x20000220 = 0; *(uint64_t*)0x20000228 = 0; *(uint32_t*)0x20000230 = 0x4000000; syscall(__NR_sendmsg, r[0], 0x20000200ul, 0x940ul); return 0; }