// https://syzkaller.appspot.com/bug?id=826185a3ca17eb363147ce23a041ca1389b89ce3 // 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 #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"); } static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2) { if (a0 == 0xc || a0 == 0xb) { char buf[128]; sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1, (uint8_t)a2); return open(buf, O_RDWR, 0); } else { char buf[1024]; char* hash; strncpy(buf, (char*)a0, sizeof(buf) - 1); buf[sizeof(buf) - 1] = 0; while ((hash = strchr(buf, '#'))) { *hash = '0' + (char)(a1 % 10); a1 /= 10; } return open(buf, a2, 0); } } uint64_t r[1] = {0xffffffffffffffff}; int main(void) { syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); intptr_t res = 0; memcpy((void*)0x20000040, "/dev/swradio#\000", 14); res = syz_open_dev(0x20000040, 0, 2); if (res != -1) r[0] = res; *(uint32_t*)0x20000240 = 0; *(uint32_t*)0x20000244 = 9; *(uint32_t*)0x20000248 = 1; *(uint32_t*)0x20000250 = 0xb; *(uint32_t*)0x20000258 = 0; *(uint32_t*)0x2000025c = 1; *(uint32_t*)0x20000260 = 0; *(uint32_t*)0x20000264 = 0; *(uint32_t*)0x20000268 = 0; *(uint32_t*)0x2000026c = 0; *(uint32_t*)0x20000270 = 0; *(uint32_t*)0x20000274 = 0; *(uint32_t*)0x20000278 = 0; *(uint32_t*)0x2000027c = 0; *(uint32_t*)0x20000280 = 0; *(uint32_t*)0x20000284 = 0; *(uint32_t*)0x20000320 = 0; *(uint32_t*)0x20000324 = 0; *(uint32_t*)0x20000328 = 0; *(uint32_t*)0x2000032c = 0; *(uint32_t*)0x20000330 = 0; *(uint32_t*)0x20000334 = 0; *(uint32_t*)0x20000338 = 0; *(uint32_t*)0x2000033c = 0; syscall(__NR_ioctl, r[0], 0xc100565cul, 0x20000240ul); *(uint32_t*)0x20000080 = 0; *(uint32_t*)0x20000084 = 7; *(uint32_t*)0x20000088 = 4; *(uint32_t*)0x20000090 = 0xb; memcpy((void*)0x20000098, "\x14\xfc\x58\xf1\x28\xe5\x22\x3c\x7e\x54\x61\xc1\xde\xb1\x2c\xe3\x35" "\xf6\x2b\x63\x77\x70\xf6\x0a\x8a\xff\xae\x2d\x1b\xc8\x14\x41\x13\x6a" "\x91\x14\x4f\xd1\xb0\x65\x62\xaf\x3b\xc8\x12\xfd\x93\x1b\xb7\x4e\x88" "\x5c\xaf\x25\xe0\x48\x9e\x79\xcb\xe5\xfe\x93\xff\xb5\x42\x66\x0a\xbf" "\x40\x6d\x45\xac\xf6\xc0\x89\xef\x7d\x24\x2f\xce\x2a\xf0\xdc\x66\x23" "\x48\xa0\xaa\x77\x0e\x6c\x5e\x3b\x62\x21\xf2\xb7\x12\x7d\x58\x29\x72" "\xd1\x33\x64\x43\x41\x68\x01\x7a\x7c\xd4\xf5\x9b\x0e\x98\x4d\x8c\xea" "\xb1\x4f\x2b\xfb\x0e\xe1\x3b\xc9\x93\x50\x9f\x1b\x40\xfb\xec\x11\x45" "\x47\x39\x08\xcb\xb3\x63\xf4\xa5\xb9\xed\xa2\x49\x0b\x6e\x7b\xf3\xb2" "\x81\xfc\x35\xd0\xca\x4b\xaa\xf9\x8c\x19\xa8\xb1\x12\x6f\x18\x28\xb8" "\xa3\xd1\xdc\x60\x7f\xb5\xf1\x67\x1b\x16\x8e\xe5\x1e\x9c\x1f\x60\x72" "\x30\x09\x29\x4f\x9d\x74\xef\x3e\x03\xea\xbd\x5a\x33", 200); *(uint32_t*)0x20000160 = 0; *(uint32_t*)0x20000164 = 0; *(uint32_t*)0x20000168 = 0; *(uint32_t*)0x2000016c = 0; *(uint32_t*)0x20000170 = 0; *(uint32_t*)0x20000174 = 0; *(uint32_t*)0x20000178 = 0; *(uint32_t*)0x2000017c = 0; syscall(__NR_ioctl, r[0], 0xc100565cul, 0x20000080ul); return 0; }