// https://syzkaller.appspot.com/bug?id=69d287b126835946ecf458d5ddda186ffd0783b6 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Manually declare if_nameindex to avoid including , * which conflicts with and causes redefinition errors. */ struct if_nameindex { unsigned int if_index; char *if_name; }; extern struct if_nameindex *if_nameindex(void); extern void if_freenameindex(struct if_nameindex *ptr); static int trigger_netdevsim_autoload(void) { int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock < 0) return -1; struct { struct nlmsghdr nlh; struct ifinfomsg ifm; char attrbuf[128]; } req; memset(&req, 0, sizeof(req)); req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK; req.nlh.nlmsg_type = RTM_NEWLINK; req.ifm.ifi_family = AF_UNSPEC; struct rtattr *linkinfo = (struct rtattr *)(((char *)&req) + req.nlh.nlmsg_len); linkinfo->rta_type = IFLA_LINKINFO; linkinfo->rta_len = RTA_LENGTH(0); req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_LENGTH(0); struct rtattr *infokind = (struct rtattr *)(((char *)&req) + req.nlh.nlmsg_len); infokind->rta_type = IFLA_INFO_KIND; const char *kind = "netdevsim"; int kind_len = strlen(kind) + 1; infokind->rta_len = RTA_LENGTH(kind_len); memcpy(RTA_DATA(infokind), kind, kind_len); req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + RTA_LENGTH(kind_len); linkinfo->rta_len = (char *)infokind + infokind->rta_len - (char *)linkinfo; send(sock, &req, req.nlh.nlmsg_len, 0); close(sock); return 0; } static volatile int stop = 0; static void *suspend_thread(void *arg) { int fd = open("/sys/power/state", O_WRONLY); if (fd < 0) { printf("[-] Failed to open /sys/power/state: %s\n", strerror(errno)); return NULL; } while (!stop) { if (write(fd, "freeze", 6) < 0) { // Might fail if already freezing or not supported, just ignore } usleep(10000); // 10ms } close(fd); return NULL; } static void *flash_thread(void *arg) { int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { printf("[-] Failed to create socket: %s\n", strerror(errno)); return NULL; } struct ethtool_flash efl; memset(&efl, 0, sizeof(efl)); efl.cmd = ETHTOOL_FLASHDEV; strcpy(efl.data, "nonexistent_fw.bin"); while (!stop) { struct if_nameindex *if_ni = if_nameindex(); if (if_ni) { for (struct if_nameindex *i = if_ni; i->if_index != 0 || i->if_name != NULL; i++) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, i->if_name, IFNAMSIZ - 1); ifr.ifr_data = (void *)&efl; ioctl(sock, SIOCETHTOOL, &ifr); } if_freenameindex(if_ni); } } close(sock); return NULL; } int main(void) { printf("[*] Setting up netdevsim...\n"); int fd = open("/sys/bus/netdevsim/new_device", O_WRONLY); if (fd < 0) { trigger_netdevsim_autoload(); sleep(1); fd = open("/sys/bus/netdevsim/new_device", O_WRONLY); } if (fd >= 0) { if (dprintf(fd, "1 1\n") < 0) { printf("[-] Failed to write to new_device: %s\n", strerror(errno)); } else { printf("[+] Created netdevsim device.\n"); } close(fd); } else { printf("[-] Failed to open /sys/bus/netdevsim/new_device: %s\n", strerror(errno)); } sleep(1); // Wait for interface to appear pthread_t t_suspend; pthread_t t_flash[4]; printf("[*] Starting threads...\n"); pthread_create(&t_suspend, NULL, suspend_thread, NULL); for (int i = 0; i < 4; i++) { pthread_create(&t_flash[i], NULL, flash_thread, NULL); } sleep(10); stop = 1; pthread_join(t_suspend, NULL); for (int i = 0; i < 4; i++) { pthread_join(t_flash[i], NULL); } printf("[*] Cleaning up...\n"); fd = open("/sys/bus/netdevsim/del_device", O_WRONLY); if (fd >= 0) { dprintf(fd, "1\n"); close(fd); } printf("[+] Done.\n"); return 0; }