// https://syzkaller.appspot.com/bug?id=233388d0f8c73c0d468e359c3641bf3cf23c8dea #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include int main(void) { int sysfs_fd; int pipefd[2]; char data[256]; pid_t pid1, pid2; // 1. Create pipe if (pipe(pipefd) < 0) { printf("[-] Failed to create pipe: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully created pipe\n"); // 2. Mount autofs if (mkdir("/tmp/autofs_mnt", 0777) < 0 && errno != EEXIST) { printf("[-] Failed to mkdir /tmp/autofs_mnt: %s\n", strerror(errno)); exit(1); } snprintf(data, sizeof(data), "fd=%d,pgrp=%d,minproto=5,maxproto=5", pipefd[1], getpgrp()); if (mount("autofs", "/tmp/autofs_mnt", "autofs", 0, data) < 0) { printf("[-] Failed to mount autofs: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully mounted autofs\n"); // 3. Open /sys/power/resume sysfs_fd = open("/sys/power/resume", O_WRONLY); if (sysfs_fd < 0) { printf("[-] Failed to open /sys/power/resume: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully opened /sys/power/resume\n"); // Step 1: Trigger normal automount to record sbi->pipe_mutex -> pipe->mutex pid1 = fork(); if (pid1 < 0) { printf("[-] Failed to fork pid1: %s\n", strerror(errno)); exit(1); } if (pid1 == 0) { // Isolate process group so autofs_oz_mode() returns false if (setpgid(0, 0) < 0) { printf("[-] Failed to setpgid: %s\n", strerror(errno)); exit(1); } struct stat st; printf("[+] Child 1: stat /tmp/autofs_mnt/test1...\n"); stat("/tmp/autofs_mnt/test1", &st); exit(0); } // Wait for Child 1 to trigger automount and block usleep(500000); // 500ms // Step 2: Run splice to record pipe->mutex -> of->mutex printf("[+] Parent: writing to pipe...\n"); if (write(pipefd[1], "A", 1) < 0) { printf("[-] Failed to write to pipe: %s\n", strerror(errno)); } printf("[+] Parent: splicing from pipe to sysfs_fd...\n"); if (splice(pipefd[0], NULL, sysfs_fd, NULL, 1, 0) < 0) { printf("[+] Parent splice returned (expected error): %s\n", strerror(errno)); } else { printf("[+] Parent splice completed successfully\n"); } // Step 3: Run write to sysfs_fd to trigger the splat pid2 = fork(); if (pid2 < 0) { printf("[-] Failed to fork pid2: %s\n", strerror(errno)); exit(1); } if (pid2 == 0) { // Isolate process group so autofs_oz_mode() returns false if (setpgid(0, 0) < 0) { printf("[-] Failed to setpgid: %s\n", strerror(errno)); exit(1); } const char *path = "/tmp/autofs_mnt/test2\n"; printf("[+] Child 2: writing to sysfs_fd...\n"); if (write(sysfs_fd, path, strlen(path)) < 0) { printf("[-] Child 2 write failed: %s\n", strerror(errno)); } exit(0); } // Wait for Child 2 to trigger the lockdep splat usleep(500000); // 500ms // Clean up kill(pid1, SIGKILL); kill(pid2, SIGKILL); waitpid(pid1, NULL, 0); waitpid(pid2, NULL, 0); umount2("/tmp/autofs_mnt", MNT_DETACH); rmdir("/tmp/autofs_mnt"); close(sysfs_fd); close(pipefd[0]); close(pipefd[1]); printf("[+] Done\n"); return 0; }