// https://syzkaller.appspot.com/bug?id=5ad3dc0db2152702bfdc671e6fad58df70304c6b #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef LOOP_SET_DIRECT_IO #define LOOP_SET_DIRECT_IO 0x4C08 #endif int dev_fd, fd_source; void *mapped; volatile int stop = 0; void *thread1(void *arg) { while (!stop) { // O_DIRECT write to loop device, reading from ramfs page cache pwrite(dev_fd, mapped, 4096, 0); } return NULL; } void *thread2(void *arg) { char buf[4096] = {1}; while (!stop) { // Buffered write to ramfs file, writing to ramfs page cache pwrite(fd_source, buf, 4096, 0); } return NULL; } int main() { setvbuf(stdout, NULL, _IONBF, 0); // 1. Create backing file (shmem) int fd_backing = syscall(SYS_memfd_create, "backing", 0); if (fd_backing < 0) { printf("[-] Failed to memfd_create: %s\n", strerror(errno)); exit(1); } printf("[+] memfd_create successful.\n"); if (ftruncate(fd_backing, 1024 * 1024) < 0) { printf("[-] Failed to ftruncate backing: %s\n", strerror(errno)); exit(1); } printf("[+] ftruncate backing successful.\n"); // 2. Set up loop device int loop_ctl = open("/dev/loop-control", O_RDWR); if (loop_ctl < 0) { printf("[-] Failed to open /dev/loop-control: %s\n", strerror(errno)); exit(1); } printf("[+] open /dev/loop-control successful.\n"); int dev_nr = ioctl(loop_ctl, LOOP_CTL_GET_FREE); if (dev_nr < 0) { printf("[-] Failed to ioctl LOOP_CTL_GET_FREE: %s\n", strerror(errno)); exit(1); } printf("[+] ioctl LOOP_CTL_GET_FREE successful, dev_nr=%d.\n", dev_nr); char loop_name[64]; sprintf(loop_name, "/dev/loop%d", dev_nr); int loop_fd = open(loop_name, O_RDWR); if (loop_fd < 0) { printf("[-] Failed to open loop device %s: %s\n", loop_name, strerror(errno)); exit(1); } printf("[+] open loop device successful.\n"); if (ioctl(loop_fd, LOOP_SET_FD, fd_backing) < 0) { printf("[-] Failed to ioctl LOOP_SET_FD: %s\n", strerror(errno)); exit(1); } printf("[+] ioctl LOOP_SET_FD successful.\n"); if (ioctl(loop_fd, LOOP_SET_DIRECT_IO, 1) < 0) { printf("[-] Failed to ioctl LOOP_SET_DIRECT_IO: %s\n", strerror(errno)); // Ignore error, it might still work or not be supported } else { printf("[+] ioctl LOOP_SET_DIRECT_IO successful.\n"); } // Re-open loop device with O_DIRECT dev_fd = open(loop_name, O_RDWR | O_DIRECT); if (dev_fd < 0) { printf("[-] Failed to open loop device O_DIRECT: %s\n", strerror(errno)); exit(1); } printf("[+] open loop device O_DIRECT successful.\n"); // 3. Mount ramfs and create source file if (mkdir("./ramfs_test", 0777) < 0 && errno != EEXIST) { printf("[-] Failed to mkdir ./ramfs_test: %s\n", strerror(errno)); exit(1); } printf("[+] mkdir ./ramfs_test successful.\n"); if (mount("ramfs", "./ramfs_test", "ramfs", 0, "") < 0) { printf("[-] Failed to mount ramfs: %s\n", strerror(errno)); exit(1); } printf("[+] mount ramfs successful.\n"); fd_source = open("./ramfs_test/file", O_RDWR | O_CREAT, 0666); if (fd_source < 0) { printf("[-] Failed to open ramfs file: %s\n", strerror(errno)); exit(1); } printf("[+] open ramfs file successful.\n"); if (ftruncate(fd_source, 1024 * 1024) < 0) { printf("[-] Failed to ftruncate ramfs file: %s\n", strerror(errno)); exit(1); } printf("[+] ftruncate ramfs file successful.\n"); // 4. Map source file mapped = mmap(NULL, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd_source, 0); if (mapped == MAP_FAILED) { printf("[-] Failed to mmap: %s\n", strerror(errno)); exit(1); } printf("[+] mmap successful.\n"); // 5. Trigger the race pthread_t t1, t2; pthread_create(&t1, NULL, thread1, NULL); pthread_create(&t2, NULL, thread2, NULL); sleep(3); // Run for 3 seconds to trigger KCSAN stop = 1; pthread_join(t1, NULL); pthread_join(t2, NULL); // Cleanup ioctl(loop_fd, LOOP_CLR_FD, 0); close(loop_fd); close(dev_fd); close(fd_source); close(fd_backing); umount("./ramfs_test"); rmdir("./ramfs_test"); printf("[+] Done.\n"); return 0; }