// https://syzkaller.appspot.com/bug?id=a174cc81e1864137a961f23b7efa47432115c7ec #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int main(void) { setvbuf(stdout, NULL, _IONBF, 0); printf("[*] Starting reproducer for circular locking dependency in blk_request_module...\n"); /* Step 1: Create backing memory file for loop device */ int memfd = memfd_create("loop_backing", 0); if (memfd < 0) { printf("[-] Failed to memfd_create: %s\n", strerror(errno)); exit(1); } printf("[+] memfd_create successful, fd=%d.\n", memfd); int res = ftruncate(memfd, 16 * 1024 * 1024); if (res < 0) { printf("[-] Failed to ftruncate memfd: %s\n", strerror(errno)); exit(1); } printf("[+] ftruncate (16MB) successful.\n"); /* Step 2: Acquire a free loop device */ int loop_ctl_fd = open("/dev/loop-control", O_RDWR); if (loop_ctl_fd < 0) { printf("[-] Failed to open /dev/loop-control: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully opened /dev/loop-control.\n"); int loop_nr = ioctl(loop_ctl_fd, LOOP_CTL_GET_FREE); if (loop_nr < 0) { printf("[-] Failed to ioctl(LOOP_CTL_GET_FREE): %s\n", strerror(errno)); exit(1); } printf("[+] LOOP_CTL_GET_FREE successful, acquired loop%d.\n", loop_nr); close(loop_ctl_fd); /* Step 3: Attach loop device to backing file */ char loop_path[64]; snprintf(loop_path, sizeof(loop_path), "/dev/loop%d", loop_nr); int loop_fd = open(loop_path, O_RDWR); if (loop_fd < 0) { printf("[-] Failed to open %s: %s\n", loop_path, strerror(errno)); exit(1); } printf("[+] Successfully opened %s.\n", loop_path); res = ioctl(loop_fd, LOOP_SET_FD, memfd); if (res < 0) { printf("[-] Failed to ioctl(LOOP_SET_FD): %s\n", strerror(errno)); exit(1); } printf("[+] LOOP_SET_FD successful.\n"); struct stat st; res = fstat(loop_fd, &st); if (res < 0) { printf("[-] Failed to fstat loop device: %s\n", strerror(errno)); exit(1); } int loop_maj = major(st.st_rdev); int loop_min = minor(st.st_rdev); printf("[+] Backing device ready: major=%d, minor=%d.\n", loop_maj, loop_min); /* Step 4: Create and open an unallocated MD node to establish major_names_lock -> md_misc_wq */ int md_minor = 125; char md_path[64]; snprintf(md_path, sizeof(md_path), "/tmp/md%d", md_minor); unlink(md_path); res = mknod(md_path, S_IFBLK | 0600, makedev(MD_MAJOR, md_minor)); if (res < 0) { printf("[-] Failed to mknod(%s): %s\n", md_path, strerror(errno)); exit(1); } printf("[+] mknod successful for %s (major %d, minor %d).\n", md_path, MD_MAJOR, md_minor); int md_fd = open(md_path, O_RDWR); if (md_fd < 0) { printf("[-] Failed to open %s: %s\n", md_path, strerror(errno)); exit(1); } printf("[+] Opened %s successfully (major_names_lock -> md_misc_wq chain recorded).\n", md_path); /* Step 5: Configure RAID1 metadata */ mdu_array_info_t array_info = {0}; array_info.level = 1; array_info.size = 4096; array_info.nr_disks = 1; array_info.raid_disks = 1; array_info.md_minor = md_minor; array_info.not_persistent = 1; res = ioctl(md_fd, SET_ARRAY_INFO, &array_info); if (res < 0) { printf("[-] Failed to ioctl(SET_ARRAY_INFO): %s\n", strerror(errno)); exit(1); } printf("[+] SET_ARRAY_INFO successful.\n"); /* Step 6: Add backing loop device to MD array */ mdu_disk_info_t disk_info = {0}; disk_info.number = 0; disk_info.major = loop_maj; disk_info.minor = loop_min; disk_info.raid_disk = 0; disk_info.state = (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC); res = ioctl(md_fd, ADD_NEW_DISK, &disk_info); if (res < 0) { printf("[-] Failed to ioctl(ADD_NEW_DISK) for backing disk: %s\n", strerror(errno)); exit(1); } printf("[+] ADD_NEW_DISK for backing device successful.\n"); /* Step 7: Run RAID1 array */ res = ioctl(md_fd, RUN_ARRAY, 0); if (res < 0) { printf("[-] Failed to ioctl(RUN_ARRAY): %s\n", strerror(errno)); exit(1); } printf("[+] RUN_ARRAY successful.\n"); /* Step 8: Allow raid1d and md_start_sync to execute on md_misc_wq */ printf("[*] Sleeping 1s to allow md_start_sync to acquire reconfig_mutex on md_misc_wq...\n"); sleep(1); /* Step 9: Trigger circular lockdep warning by calling ADD_NEW_DISK with dev(0,0) */ printf("[*] Issuing ADD_NEW_DISK with MKDEV(0, 0) to trigger lockdep cycle...\n"); mdu_disk_info_t bad_disk = {0}; bad_disk.number = 1; bad_disk.major = 0; bad_disk.minor = 0; bad_disk.raid_disk = 1; bad_disk.state = 0; res = ioctl(md_fd, ADD_NEW_DISK, &bad_disk); if (res < 0) { printf("[-] Failed to ioctl(ADD_NEW_DISK): %s\n", strerror(errno)); printf("[*] Lockdep circular locking dependency warning was triggered in dmesg.\n"); sleep(1); exit(1); } printf("[+] ioctl(ADD_NEW_DISK) returned successfully.\n"); return 0; }