// https://syzkaller.appspot.com/bug?id=6fcea12d84e40cf5001de61c7e3fea6f7ae69d66 // 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[2] = {0xffffffffffffffff, 0xffffffffffffffff}; int main(void) { syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 3ul, 0x32ul, -1, 0); intptr_t res = 0; res = syz_open_dev(0xc, 4, 1); if (res != -1) r[0] = res; *(uint32_t*)0x20000040 = 0; *(uint32_t*)0x20000044 = 0; *(uint32_t*)0x20000048 = 0x20; *(uint32_t*)0x2000004c = 0x13; *(uint32_t*)0x20000050 = 0x100; *(uint64_t*)0x20000058 = 0x200003c0; memcpy( (void*)0x200003c0, "\xcb\xb6\x2c\x7c\x7e\x12\x72\x7d\x60\xc5\xdb\x26\x5c\x1d\x8b\x3f\x75\x25" "\x50\xd4\xea\xc7\xaf\xf1\x02\x13\x26\xe1\x5d\xfd\xad\x91\x1d\x57\xa8\x53" "\x41\x4b\x19\x47\x02\xa4\x1a\x75\x60\x56\x8b\xe1\x11\x1d\xac\x9f\xf2\x58" "\x6d\x67\xdc\x8e\xf3\xe9\xd3\x66\x94\xc5\xea\x96\xd8\x98\x5a\x99\x53\xe8" "\x77\x5c\xbf\x7a\xe1\x51\xea\x1f\xd6\x08\x63\xac\xd9\xe7\x60\x31\x83\x3d" "\xff\xb4\x47\xc4\x25\xc9\x74\x9c\x7d\xe7\xfb\xe2\xe5\x65\xb4\xa2\x5f\x7b" "\x2a\xc0\x13\x92\xce\x04\xec\x8d\x6d\x21\x0e\x0a\x23\xae\x3a\x5f\xd8\x1c" "\x3c\x89\xc9\x28\x74\x70\x9f\xcd\xd4\xd4\xc3\xff\xe7\xfa\x05\x2a\xc6\x8f" "\xb6\x01\x7e\x48\x2e\x24\xbe\x6a\xc8\x19\x10\x39\xb4\x34\xaa\x0e\x9f\x97" "\x39\xae\xdf\x30\xc0\xfa\x9c\x42\xcd\xa4\x11\x02\x5c\xa2\x0c\x42\xbf\x88" "\x68\x56\x03\x99\x87\x3f\x4d\x1b\x28\xed\x71\x3e\x41\x1b\x34\xec\x02\x63" "\x21\xc8\xcd\x9a\xd1\x7c\xbc\x95\x70\x4c\x14\x2d\x7c\x71\x06\x3b\x4a\x0b" "\x52\xe2\x20\x73\xf8\x59\xd6\x32\x89\x92\x12\x6e\x5f\x50\x57\xad\x1d\x02" "\x29\xba\xde\xc1\xe0\x88\x0f\x47\x6f\x18\xce\x68\x55\x60\x78\xa0\x06\x7d" "\x8e\x90\x05\x7f\x56\x0b\x51\x51\xc4\x50\xe6\x55\x89\x81\x2f\x77\x9b\x50" "\xe4\xde\xd6\x60\xee\x4a\xa6\x1e\x7f\x84\xa9\xb4\xb7\x91\x83\x71\x14\x09" "\x55\x39\xfb\x55\x73\xe4\x7c\xce\x26\xdc\x38\x31\x19\x13\x99\x51\x81\xe7" "\x28\xfd\x4d\x6d\x33\x4e\x62\xfd\x0a\x82\x2f\x93\x71\xbc\xdc\x43\xc8\xa6" "\x96\x88\xa1\x1f\xc9\xf4\x3a\xfe\x64\x2c\x30\xdd\xf3\x94\x65\xb1\x3c\xf1" "\xdd\xad\xd7\x89\x70\x77\x18\x27\xf4\x45\xf0\xd4\x56\x1e\x8e\x2b\xb6\xcf" "\x22\x44\x63\x4b\xcd\x72\xd1\x24\xf3\xca\xa1\x52\xc6\xfd\x6d\x47\xbb\x00" "\x4b\x97\x97\x5d\x4a\x46\xb2\xee\x12\x9b\x88\x9d\xc5\x9c\x1c\x71\x62\xff" "\xf2\x2c\x42\x95\x54\x52\x95\xea\x72\xfe\x14\xc6\xb2\xba\xb3\x5a\xb5\x45" "\x51\x73\x98\xb0\x03\xb6\xd3\xb8\x9c\x5c\x64\xb4\x49\xf7\xd5\x60\xdd\xe2" "\x0f\xc1\x3b\x3e\xc8\x8d\xc0\x52\x42\xa1\x60\x07\x6c\xcb\xff\x3e\x32\xb8" "\x78\x0b\xd1\x91\xa0\xb1\x2a\x6f\x99\x00\xa9\x37\xa1\x2d\x9f\xb5\xed\x34" "\x88\xd5\xcd\x0a\xa3\x29\x58\x3f\x2c\x47\xc4\xfd\x47\x26\x46\x9c\x98\xe0" "\xb6\x6d\x74\xc3\x1d\x0a\x1f\x7f\xc1\x0c\xc1\x94\x4d\x25\x26\x7e\xff\x7a" "\x74\x0c\xc4\x13\x06\x9b\x58\x47\x9c\xa6\x96\x00\x63\x6a\x0f\x22\xa4\x70" "\xa6\x9b\x46\xc1\xcc\x1b\x95\xcf\x32\xdd\x7b\x73\xad\x67\x41\x61\xca\x39" "\x25\x83\xaa\x83\x4a\xaa\xde\x88\xa4\x39\x33\x89\xb7\x6d\x58\x8a\x60\x81" "\x91\xdb\x7c\xa7\x5d\xd0\x09\x38\x2a\x45\x83\xe8\x78\x1e\xb0\x9f\x48\xa4" "\x4d\x06\xb4\x17\x56\xeb\x3f\x1b\x7e\xea\x18\xad\xf2\x97\x83\x22\xd0\xb3" "\x84\xdf\x03\x07\x98\x91\xe1\x0f\x09\x2c\x57\x33\x20\xfb\x94\x1f\x10\xe3" "\xc3\xaf\x6f\x3e\x72\xb2\xaf\xcd\x95\xa3\x66\x6a\x6a\x40\xa8\x40\xe6\x3d" "\x1c\xb9\xe2\x49\x25\xc0\x49\x7a\x04\xef\x7b\x9b\x1e\xe3\x9d\xe0\x45\x6f" "\xec\xd6\x76\xac\xee\x23\x3f\x5b\x64\x5e\x8d\x05\xf3\xf5\x05\xa1\x2a\x0f" "\x5b\x35\x65\x86\xf2\x2c\x2c\x2c\xeb\xef\x83\xc5\xe6\x8c\x22\x72\x34\x95" "\xab\xa0\x64\x27\x92\x55\xde\x48\x9e\x33\xe9\x20\x9a\x63\x68\x90\xbc\xfb" "\x2a\x52\x7e\x8d\xa8\x36\x21\xae\xf3\x74\xf5\xa1\x1d\x8a\xc7\x7f\x5d\xcd" "\x42\x1f\x45\xe5\x2d\xdf\x9b\xc3\x5f\x64\xcf\x72\x1c\xe6\xc9\x6b\x56\x13" "\x26\x8c\x02\x5c\xa9\x91\x0a\x8a\x23\x5e\x6a\xf3\xd6\x7a\xdd\xc6\x6e\x75" "\xc1\x56\x4a\x7f\x86\x84\xfc\xd2\x3e\xc9\x8d\x61\xa4\xfa\x42\x2c\x55\xe6" "\x78\x9c\xbc\x42\xb1\xd5\x32\x63\x3e\x65\x8a\x5c\x2f\xfe\x57\x67\x03\x97" "\x62\xf1\x8c\xce\x89\xb8\x00\x0e\x37\xca\xbc\x35\x40\x9d\x3c\x7a\x02\x13" "\xde\x87\xce\x95\xcf\xbf\xb0\xc7\x1b\xe4\xc4\xef\x44\x86\x6b\xd8\xe0\x50" "\xe3\x36\xb3\x1a\x6e\x8f\x15\xbd\x21\x60\xef\x48\x48\xad\xa2\x56\xdf\x90" "\x27\x58\xeb\xbc\x1e\x83\x7f\xab\x4c\xb8\xbb\x84\x67\xa7\x3d\xf7\x17\xd9" "\x2e\x22\x04\x48\x2f\xe9\x5c\x21\x12\x11\x86\xa5\x7c\x3b\x12\xf7\x5c\x83" "\x6a\xb7\x02\x43\x34\x18\xf3\x29\x44\x32\x3e\xaa\xad\xbc\xa3\x66\x96\x1c" "\x25\x62\x0c\x43\x95\x1a\x7a\x3f\xd3\xe3\xcc\x85\xd6\xa3\x99\x6b\x50\xd1" "\x2e\xa7\x6d\xf6\x58\xa6\x40\x5f\xdf\x1c\x9f\x2c\x05\x24\x8d\x95\x15\xce" "\x96\x65\x0e\xbf\x62\x96\x64\xe6\xc1\x92\xdd\x28\xe1\x61\x72\xbe\x15\x93" "\xe9\x4d\xbc\xa0\xe5\x54\xfc\xe9\x73\x6c\x73\x54\x03\x0c\x64\xfd\xaf\x35" "\x03\x8e\x1f\x1e\x1d\x20\xe0\x6f\x34\x8e\xf5\xae\x75\x41\x39\xb4\xe8\x12" "\xc6\x0f\xbc\x55\xba\xce\x83\xf2\x7b\xb8\x35\xc1\x64\xc2\x9f\x5f\x7c\x1d" "\xbe\xeb\xfd\x98\x8a\x16\x23\x5c\x4b\xbe\xe4\xd9\xa3\xbc\x66\x6f", 1024); syscall(__NR_ioctl, r[0], 0x4b72ul, 0x20000040ul); res = syz_open_dev(0xc, 4, 1); if (res != -1) r[1] = res; *(uint32_t*)0x20000000 = 3; *(uint32_t*)0x20000004 = 1; *(uint32_t*)0x20000008 = 0xfffffffe; *(uint32_t*)0x2000000c = 5; *(uint32_t*)0x20000010 = 0x40193; *(uint64_t*)0x20000018 = 0; syscall(__NR_ioctl, r[1], 0x4b72ul, 0x20000000ul); return 0; }