// https://syzkaller.appspot.com/bug?id=27d169aaea133352336ba40fdfea78d27108023c #define _GNU_SOURCE #include #include #include #include #include #include #include #include int write_file(const char *path, const char *data) { int fd = open(path, O_WRONLY); if (fd < 0) { return -1; } ssize_t ret = write(fd, data, strlen(data)); int err = errno; close(fd); errno = err; return ret < 0 ? -1 : 0; } int main() { struct stat st; if (stat("/sys/bus/pci/drivers/e1000e", &st) != 0) { printf("[-] e1000e driver not found in sysfs.\n"); exit(1); } DIR *dir = opendir("/sys/bus/pci/devices"); if (!dir) { printf("[-] Failed to opendir /sys/bus/pci/devices: %s\n", strerror(errno)); exit(1); } printf("[+] opendir /sys/bus/pci/devices successful.\n"); struct dirent *ent; char target_dev[256] = {0}; char best_vendor_id[32] = {0}; char best_device_id[32] = {0}; int best_score = -1; while ((ent = readdir(dir)) != NULL) { if (ent->d_name[0] == '.') continue; char path[512]; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/class", ent->d_name); FILE *f = fopen(path, "r"); if (!f) continue; unsigned int class_val = 0; char line[256]; if (fgets(line, sizeof(line), f)) { char *p = line; if (strncmp(p, "0x", 2) == 0) p += 2; sscanf(p, "%x", &class_val); } fclose(f); unsigned int base_class = class_val >> 16; // Skip Storage (0x01), Display (0x03), and Bridge (0x06) if (base_class == 0x01 || base_class == 0x03 || base_class == 0x06) { continue; } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/resource", ent->d_name); f = fopen(path, "r"); if (!f) continue; unsigned long long start = 0, end = 0, flags = 0; // Read only the first line (BAR 0) if (fgets(line, sizeof(line), f)) { if (sscanf(line, "0x%llx 0x%llx 0x%llx", &start, &end, &flags) != 3) { sscanf(line, "%llx %llx %llx", &start, &end, &flags); } // Skip empty resources if (flags == 0) { fclose(f); continue; } unsigned long long size = 0; if (start <= end) size = end - start + 1; // We need a device with a non-zero BAR 0 size that is smaller than 0x5820 (MANC register offset) if (size > 0 && size < 0x5000) { int score = 0; if (flags & 0x200) score += 10; // MMIO is best if (base_class == 0x04) score += 5; // Prefer audio if (base_class == 0x02) score += 1; // Network is okay if (score > best_score) { char vendor_id[32] = {0}; char device_id[32] = {0}; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/vendor", ent->d_name); FILE *fv = fopen(path, "r"); if (fv) { if (fgets(line, sizeof(line), fv)) { sscanf(line, "%s", vendor_id); } fclose(fv); } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/device", ent->d_name); FILE *fd = fopen(path, "r"); if (fd) { if (fgets(line, sizeof(line), fd)) { sscanf(line, "%s", device_id); } fclose(fd); } if (vendor_id[0] != '\0' && device_id[0] != '\0') { best_score = score; strncpy(target_dev, ent->d_name, sizeof(target_dev) - 1); strncpy(best_vendor_id, vendor_id, sizeof(best_vendor_id) - 1); strncpy(best_device_id, device_id, sizeof(best_device_id) - 1); } } } } fclose(f); } closedir(dir); if (target_dev[0] == '\0') { printf("[-] No suitable PCI device found.\n"); exit(1); } printf("[+] Found suitable PCI device: %s (Vendor: %s, Device: %s, Score: %d)\n", target_dev, best_vendor_id, best_device_id, best_score); char path[512]; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/driver/unbind", target_dev); write_file(path, target_dev); printf("[+] Unbound device %s from its current driver (if any).\n", target_dev); char new_id_data[256]; // driver_data = 0 corresponds to board_82571 snprintf(new_id_data, sizeof(new_id_data), "%s %s FFFFFFFF FFFFFFFF 0 0 0\n", best_vendor_id, best_device_id); if (write_file("/sys/bus/pci/drivers/e1000e/new_id", new_id_data) < 0) { printf("[-] Failed to write to new_id: %s\n", strerror(errno)); } else { printf("[+] Registered new ID to e1000e: %s", new_id_data); } if (write_file("/sys/bus/pci/drivers/e1000e/bind", target_dev) < 0) { printf("[-] Bind returned error (expected if probe crashes): %s\n", strerror(errno)); } else { printf("[+] Bound device %s to e1000e.\n", target_dev); } sleep(3); printf("[+] Done.\n"); return 0; }