int mount_fstab_main(int argc, char *argv[]) { int opt; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int long_index = 0; while ((opt = getopt_long(argc, argv, "h", long_options, &long_index)) != -1) { switch (opt) { case 'h': mount_fstab_usage(0); return EXIT_SUCCESS; default: mount_fstab_usage(1); return EXIT_FAILURE; } } // We only expect one argument if (argc - optind != 1) { mount_fstab_usage(1); return EXIT_FAILURE; } // Use the kernel log since logcat hasn't run yet util::log_set_logger(std::make_shared<util::KmsgLogger>()); // Patch SELinux policy if (!patch_loaded_sepolicy()) { LOGE("Failed to patch loaded SELinux policy. Continuing anyway"); } else { LOGV("SELinux policy patching completed"); } #if FORCE_SELINUX_PERMISSIVE int fd = open("/sys/fs/selinux/enforce", O_RDWR); if (fd > 0) { write(fd, "0", 1); close(fd); } #endif if (!mount_fstab(argv[optind])) { LOGE("Failed to mount filesystems. Rebooting into recovery"); reboot_directly("recovery"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
Installer::ProceedState RecoveryInstaller::on_initialize() { struct stat sb; if (stat("/sys/fs/selinux", &sb) == 0) { if (!patch_loaded_sepolicy(SELinuxPatch::CWM_RECOVERY)) { LOGE("Failed to patch sepolicy. Trying to disable SELinux"); int fd = open(SELINUX_ENFORCE_FILE, O_WRONLY | O_CLOEXEC); if (fd >= 0) { write(fd, "0", 1); close(fd); } else { LOGE("Failed to set SELinux to permissive mode"); display_msg("Could not patch or disable SELinux"); } } } return ProceedState::Continue; }
int daemon_main(int argc, char *argv[]) { int opt; bool fork_flag = false; bool replace_flag = false; bool patch_sepolicy = true; enum { OPT_ALLOW_ROOT_CLIENT = 1000, OPT_NO_PATCH_SEPOLICY = 1001, OPT_SIGSTOP_WHEN_READY = 1002, OPT_LOG_TO_KMSG = 1003, OPT_LOG_TO_STDIO = 1004, OPT_NO_UNSHARE = 1005, }; static struct option long_options[] = { {"daemonize", no_argument, 0, 'd'}, {"replace", no_argument, 0, 'r'}, {"help", no_argument, 0, 'h'}, {"allow-root-client", no_argument, 0, OPT_ALLOW_ROOT_CLIENT}, {"no-patch-sepolicy", no_argument, 0, OPT_NO_PATCH_SEPOLICY}, {"sigstop-when-ready", no_argument, 0, OPT_SIGSTOP_WHEN_READY}, {"log-to-kmsg", no_argument, 0, OPT_LOG_TO_KMSG}, {"log-to-stdio", no_argument, 0, OPT_LOG_TO_STDIO}, {"no-unshare", no_argument, 0, OPT_NO_UNSHARE}, {0, 0, 0, 0} }; int long_index = 0; while ((opt = getopt_long(argc, argv, "drh", long_options, &long_index)) != -1) { switch (opt) { case 'd': fork_flag = true; break; case 'r': replace_flag = true; break; case 'h': daemon_usage(0); return EXIT_SUCCESS; case OPT_ALLOW_ROOT_CLIENT: allow_root_client = true; break; case OPT_NO_PATCH_SEPOLICY: patch_sepolicy = false; break; case OPT_SIGSTOP_WHEN_READY: sigstop_when_ready = true; break; case OPT_LOG_TO_KMSG: log_to_kmsg = true; break; case OPT_LOG_TO_STDIO: log_to_stdio = true; break; case OPT_NO_UNSHARE: no_unshare = true; break; default: daemon_usage(1); return EXIT_FAILURE; } } // There should be no other arguments if (argc - optind != 0) { daemon_usage(1); return EXIT_FAILURE; } if (!no_unshare && unshare(CLONE_NEWNS) < 0) { fprintf(stderr, "unshare() failed: %s\n", strerror(errno)); return EXIT_FAILURE; } if (patch_sepolicy) { patch_loaded_sepolicy(SELinuxPatch::MAIN); } if (!switch_context(MB_EXEC_CONTEXT)) { fprintf(stderr, "Failed to switch context; %s may not run properly", argv[0]); } if (replace_flag) { PROCTAB *proc = openproc(PROC_FILLCOM | PROC_FILLSTAT); if (proc) { pid_t curpid = getpid(); while (proc_t *info = readproc(proc, nullptr)) { // NOTE: Can't check 'strcmp(info->cmd, "mbtool") == 0' (which // is the basename of /proc/<pid>/cmd) because the binary is not // always called "mbtool". For example, when run via SignedExec, // it's just called "binary". // If we can read the cmdline and argc >= 2 if (info->cmdline && info->cmdline[0] && info->cmdline[1]) { const char *name = strrchr(info->cmdline[0], '/'); if (name) { ++name; } else { name = info->cmdline[0]; } if (strcmp(name, "mbtool") == 0 // This is mbtool && strstr(info->cmdline[1], "daemon") // And it's a daemon process && info->tid != curpid) { // And we're not killing ourself // Kill the daemon process LOGV("Killing PID %d", info->tid); kill(info->tid, SIGTERM); } } freeproc(info); } closeproc(proc); } // Give processes a chance to exit usleep(500000); } if (fork_flag) { run_daemon_fork(); } else { return (daemon_init() && run_daemon()) ? EXIT_SUCCESS : EXIT_FAILURE; } }
int sepolpatch_main(int argc, char *argv[]) { int opt; int loaded_flag = 0; const char *source_file = nullptr; const char *target_file = nullptr; static struct option long_options[] = { {"loaded", no_argument, 0, 'l'}, {"source", required_argument, 0, 's'}, {"target", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int long_index = 0; while ((opt = getopt_long(argc, argv, "ls:t:h", long_options, &long_index)) != -1) { switch (opt) { case 'l': loaded_flag = 1; break; case 's': source_file = optarg; break; case 't': target_file = optarg; break; case 'h': sepolpatch_usage(0); return EXIT_SUCCESS; default: sepolpatch_usage(1); return EXIT_FAILURE; } } // There should be no other arguments if (argc - optind != 0) { sepolpatch_usage(1); return EXIT_FAILURE; } if (!loaded_flag && !source_file && !target_file) { sepolpatch_usage(1); return EXIT_FAILURE; } if (loaded_flag) { if (source_file || target_file) { fprintf(stderr, "'--source' and '--target' cannot be used with '--loaded'\n"); return EXIT_FAILURE; } return patch_loaded_sepolicy() == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } if (!source_file) { source_file = SELINUX_POLICY_FILE; } if (!target_file) { target_file = SELINUX_LOAD_FILE; } return patch_sepolicy(source_file, target_file) ? EXIT_SUCCESS : EXIT_FAILURE; }
int daemon_main(int argc, char *argv[]) { int opt; bool fork_flag = false; bool replace_flag = false; static struct option long_options[] = { {"daemonize", no_argument, 0, 'd'}, {"replace", no_argument, 0, 'r'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int long_index = 0; while ((opt = getopt_long(argc, argv, "drh", long_options, &long_index)) != -1) { switch (opt) { case 'd': fork_flag = true; break; case 'r': replace_flag = true; break; case 'h': daemon_usage(0); return EXIT_SUCCESS; default: daemon_usage(1); return EXIT_FAILURE; } } // There should be no other arguments if (argc - optind != 0) { daemon_usage(1); return EXIT_FAILURE; } // Patch SELinux policy to make init permissive patch_loaded_sepolicy(); // Allow untrusted_app to connect to our daemon patch_sepolicy_daemon(); // Set version property if we're the system mbtool (i.e. launched by init) // Possible to override this with another program by double forking, letting // 2nd child reparent to init, and then calling execve("/mbtool", ...), but // meh ... if (getppid() == 1) { if (!util::set_property("ro.multiboot.version", get_mbtool_version())) { std::printf("Failed to set 'ro.multiboot.version' to '%s'\n", get_mbtool_version()); } } if (replace_flag) { PROCTAB *proc = openproc(PROC_FILLCOM | PROC_FILLSTAT); if (proc) { pid_t curpid = getpid(); while (proc_t *info = readproc(proc, nullptr)) { if (strcmp(info->cmd, "mbtool") == 0 // This is mbtool && info->cmdline // And we can see the command line && info->cmdline[1] // And argc > 1 && strstr(info->cmdline[1], "daemon") // And it's a daemon process && info->tid != curpid) { // And we're not killing ourself // Kill the daemon process std::printf("Killing PID %d\n", info->tid); kill(info->tid, SIGTERM); } freeproc(info); } closeproc(proc); } // Give processes a chance to exit usleep(500000); } // Set up logging if (!util::mkdir_parent(MULTIBOOT_LOG_DAEMON, 0775) && errno != EEXIST) { fprintf(stderr, "Failed to create parent directory of %s: %s\n", MULTIBOOT_LOG_DAEMON, strerror(errno)); return EXIT_FAILURE; } autoclose::file fp(autoclose::fopen(MULTIBOOT_LOG_DAEMON, "w")); if (!fp) { fprintf(stderr, "Failed to open log file %s: %s\n", MULTIBOOT_LOG_DAEMON, strerror(errno)); return EXIT_FAILURE; } fix_multiboot_permissions(); // mbtool logging log::log_set_logger(std::make_shared<log::StdioLogger>(fp.get(), true)); if (fork_flag) { run_daemon_fork(); } else { return run_daemon() ? EXIT_SUCCESS : EXIT_FAILURE; } }