// https://syzkaller.appspot.com/bug?id=3e420300f6b231aa906425cbb4bd55dd64f42da4 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #ifndef __NR_finit_module #define __NR_finit_module 313 #endif #define MODULE_INIT_COMPRESSED_FILE 4 void try_load(const char *path) { int fd = open(path, O_RDONLY); if (fd >= 0) { int flags = 0; if (strstr(path, ".xz") || strstr(path, ".zst")) flags = MODULE_INIT_COMPRESSED_FILE; if (syscall(__NR_finit_module, fd, "", flags) == 0) { printf("[+] Loaded module %s\n", path); } close(fd); } } void load_block2mtd(void) { struct utsname un; if (uname(&un) < 0) return; char path[512]; const char *exts[] = { ".ko", ".ko.xz", ".ko.zst" }; const char *mods[] = { "drivers/mtd/mtd", "drivers/mtd/devices/block2mtd" }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { snprintf(path, sizeof(path), "/lib/modules/%s/kernel/%s%s", un.release, mods[i], exts[j]); try_load(path); } } } int main(void) { load_block2mtd(); sleep(1); char template[] = "/tmp/ovl_bug_XXXXXX"; if (!mkdtemp(template)) { printf("[-] Failed to mkdtemp: %s\n", strerror(errno)); exit(1); } if (chdir(template) != 0) { printf("[-] Failed to chdir: %s\n", strerror(errno)); exit(1); } printf("[+] Setup working directory.\n"); if (mkdir("lower", 0777) < 0) { printf("[-] Failed to mkdir lower: %s\n", strerror(errno)); exit(1); } if (mkdir("upper", 0777) < 0) { printf("[-] Failed to mkdir upper: %s\n", strerror(errno)); exit(1); } if (mkdir("work", 0777) < 0) { printf("[-] Failed to mkdir work: %s\n", strerror(errno)); exit(1); } if (mkdir("merged", 0777) < 0) { printf("[-] Failed to mkdir merged: %s\n", strerror(errno)); exit(1); } if (mount("overlay", "merged", "overlay", 0, "lowerdir=lower,upperdir=upper,workdir=work") != 0) { printf("[-] Failed to mount overlay: %s\n", strerror(errno)); exit(1); } printf("[+] Mounted overlayfs.\n"); // 1. Establish sb_writers -> pipe->mutex int pipefd1[2]; if (pipe(pipefd1) != 0) { printf("[-] Failed to pipe1: %s\n", strerror(errno)); exit(1); } int ovl_fd = open("upper/file1", O_CREAT | O_WRONLY, 0666); if (ovl_fd < 0) { printf("[-] Failed to open upper/file1: %s\n", strerror(errno)); exit(1); } if (write(pipefd1[1], "a", 1) != 1) { printf("[-] Failed to write to pipe1: %s\n", strerror(errno)); exit(1); } if (splice(pipefd1[0], NULL, ovl_fd, NULL, 1, 0) < 0) { printf("[-] Failed to splice to ovl_fd: %s\n", strerror(errno)); } close(ovl_fd); close(pipefd1[0]); close(pipefd1[1]); printf("[+] Established sb_writers -> pipe->mutex.\n"); // 2. Establish pipe->mutex -> param_lock -> ovl_i_mutex_dir_key int pipefd2[2]; if (pipe(pipefd2) != 0) { printf("[-] Failed to pipe2: %s\n", strerror(errno)); exit(1); } int sys_fd = open("/sys/module/block2mtd/parameters/block2mtd", O_WRONLY); if (sys_fd < 0) { printf("[-] Failed to open block2mtd: %s\n", strerror(errno)); } else { char path[512]; char *cwd = getcwd(NULL, 0); if (!cwd) { printf("[-] Failed to getcwd: %s\n", strerror(errno)); exit(1); } int len = snprintf(path, sizeof(path), "%s/merged/nonexistent", cwd); if (write(pipefd2[1], path, len) != len) { printf("[-] Failed to write to pipe2: %s\n", strerror(errno)); exit(1); } if (splice(pipefd2[0], NULL, sys_fd, NULL, len, 0) < 0) { printf("[-] Failed to splice to block2mtd (expected): %s\n", strerror(errno)); } free(cwd); close(sys_fd); printf("[+] Established pipe->mutex -> param_lock -> ovl_i_mutex_dir_key.\n"); } close(pipefd2[0]); close(pipefd2[1]); // 3. Establish ovl_i_mutex_dir_key -> sb_writers int fd = open("merged/file3", O_CREAT | O_RDWR, 0644); if (fd < 0) { printf("[-] Failed to open merged/file3: %s\n", strerror(errno)); exit(1); } close(fd); printf("[+] Triggered ovl_i_mutex_dir_key -> sb_writers.\n"); // Clean up umount("merged"); printf("[+] Done.\n"); return 0; }