diff --git a/native/jni/Android.mk b/native/jni/Android.mk index ede6ca28b..31d2cdd4d 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -63,13 +63,11 @@ LOCAL_SRC_FILES := \ init/rootdir.cpp \ init/getinfo.cpp \ init/twostage.cpp \ - core/socket.cpp \ magiskpolicy/sepolicy.cpp \ magiskpolicy/magiskpolicy.cpp \ magiskpolicy/rules.cpp \ magiskpolicy/policydb.cpp \ - magiskpolicy/statement.cpp \ - magiskboot/pattern.cpp + magiskpolicy/statement.cpp LOCAL_LDFLAGS := -static include $(BUILD_EXECUTABLE) diff --git a/native/jni/init/init.hpp b/native/jni/init/init.hpp index 46927fee3..314410c09 100644 --- a/native/jni/init/init.hpp +++ b/native/jni/init/init.hpp @@ -34,7 +34,6 @@ struct fstab_entry { fstab_entry(fstab_entry &&) = default; fstab_entry &operator=(const fstab_entry&) = delete; fstab_entry &operator=(fstab_entry&&) = default; - void to_file(FILE *fp); }; #define INIT_SOCKET "MAGISKINIT" @@ -44,7 +43,6 @@ extern std::vector mount_list; bool unxz(int fd, const uint8_t *buf, size_t size); void load_kernel_info(BootConfig *config); -bool is_dsu(); bool check_two_stage(); void setup_klog(); const char *backup_init(); @@ -107,7 +105,6 @@ public: class FirstStageInit : public BaseInit { private: void prepare(); - void get_default_fstab(char *buf, size_t len); public: FirstStageInit(char *argv[], BootConfig *cmd) : BaseInit(argv, cmd) { LOGD("%s\n", __FUNCTION__); @@ -124,17 +121,14 @@ public: class SARInit : public SARBase { private: - bool is_two_stage; - - void early_mount(); + bool early_mount(); void first_stage_prep(); public: - SARInit(char *argv[], BootConfig *cmd) : MagiskInit(argv, cmd), is_two_stage(false) { + SARInit(char *argv[], BootConfig *cmd) : MagiskInit(argv, cmd) { LOGD("%s\n", __FUNCTION__); }; void start() override { - early_mount(); - if (is_two_stage) + if (early_mount()) first_stage_prep(); else patch_rootdir(); @@ -178,8 +172,10 @@ public: }; void start() override { - if (prepare()) patch_rootfs(); - else patch_rootdir(); + if (prepare()) + patch_rootfs(); + else + patch_rootdir(); exec_init(); } }; diff --git a/native/jni/init/mount.cpp b/native/jni/init/mount.cpp index 779221d35..6f6ee1955 100644 --- a/native/jni/init/mount.cpp +++ b/native/jni/init/mount.cpp @@ -205,27 +205,6 @@ static void switch_root(const string &path) { frm_rf(root); } -bool is_dsu() { - strcpy(blk_info.partname, "metadata"); - xmkdir("/metadata", 0755); - if (setup_block(true) < 0 || - xmount(blk_info.block_dev, "/metadata", "ext4", MS_RDONLY, nullptr)) { - PLOGE("Failed to mount /metadata"); - return false; - } else { - run_finally f([]{ xumount2("/metadata", MNT_DETACH); }); - constexpr auto dsu_status = "/metadata/gsi/dsu/install_status"; - if (xaccess(dsu_status, F_OK) == 0) { - char status[PATH_MAX] = {0}; - auto fp = xopen_file(dsu_status, "r"); - fgets(status, sizeof(status), fp.get()); - if (status == "ok"sv || status == "0"sv) - return true; - } - } - return false; -} - void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) { char path[128]; xrealpath(dev_base, blk_info.block_dev); @@ -327,10 +306,14 @@ void RootFSInit::early_mount() { void SARBase::backup_files() { if (access("/overlay.d", F_OK) == 0) backup_folder("/overlay.d", overlays); + else if (access("/data/overlay.d", F_OK) == 0) + backup_folder("/data/overlay.d", overlays); self = mmap_data("/proc/self/exe"); if (access("/.backup/.magisk", R_OK) == 0) magisk_config = mmap_data("/.backup/.magisk"); + else if (access("/data/.backup/.magisk", R_OK) == 0) + magisk_config = mmap_data("/data/.backup/.magisk"); } void SARBase::mount_system_root() { @@ -367,13 +350,13 @@ mount_root: xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr); } -void SARInit::early_mount() { +bool SARInit::early_mount() { backup_files(); mount_system_root(); switch_root("/system_root"); // Use the apex folder to determine whether 2SI (Android 10+) - is_two_stage = access("/apex", F_OK) == 0; + bool is_two_stage = access("/apex", F_OK) == 0; LOGD("is_two_stage: [%d]\n", is_two_stage); if (!is_two_stage) { @@ -386,26 +369,8 @@ void SARInit::early_mount() { #endif mount_with_dt(); } -} -bool SecondStageInit::prepare() { - backup_files(); - - umount2("/init", MNT_DETACH); - umount2("/proc/self/exe", MNT_DETACH); - - // some weird devices, like meizu, embrace two stage init but still have legacy rootfs behaviour - bool legacy = false; - if (access("/system_root", F_OK) == 0) { - if (access("/system_root/proc", F_OK) == 0) { - switch_root("/system_root"); - } else { - xmount("/system_root", "/system", nullptr, MS_MOVE, nullptr); - rmdir("/system_root"); - legacy = true; - } - } - return legacy; + return is_two_stage; } void BaseInit::exec_init() { diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 2e04d2452..acb031a5b 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -240,7 +240,7 @@ void SARBase::patch_rootdir() { make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */ make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */ }); - if constexpr (avd_hack) { + if (avd_hack) { // Force disable early mount on original init init.patch({ make_pair("android,fstab", "xxx") }); } @@ -276,23 +276,9 @@ void SARBase::patch_rootdir() { // sepolicy patch_sepolicy(sepol); - // Restore backup files - struct sockaddr_un sun; - int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) { - LOGD("ACK init daemon to write backup files\n"); - // Let daemon know where tmp_dir is - write_string(sockfd, tmp_dir); - // Wait for daemon to finish restoring files - read_int(sockfd); - } else { - LOGD("Restore backup files locally\n"); - restore_folder(ROOTOVL, overlays); - overlays.clear(); - } - close(sockfd); - // Handle overlay.d + restore_folder(ROOTOVL, overlays); + overlays.clear(); load_overlay_rc(ROOTOVL); if (access(ROOTOVL "/sbin", F_OK) == 0) { // Move files in overlay.d/sbin into tmp_dir diff --git a/native/jni/init/twostage.cpp b/native/jni/init/twostage.cpp index 1863378ee..8a1db385a 100644 --- a/native/jni/init/twostage.cpp +++ b/native/jni/init/twostage.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include #include @@ -10,228 +8,34 @@ using namespace std; -void fstab_entry::to_file(FILE *fp) { - fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(), - type.data(), mnt_flags.data(), fsmgr_flags.data()); -} - -#define set_info(val) \ -line[val##1] = '\0'; \ -entry.val = &line[val##0]; - -static void read_fstab_file(const char *fstab_file, vector &fstab) { - file_readline(fstab_file, [&](string_view l) -> bool { - if (l[0] == '#' || l.length() == 1) - return true; - char *line = (char *) l.data(); - - int dev0, dev1, mnt_point0, mnt_point1, type0, type1, - mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1; - - sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n", - &dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1, - &mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1); - - fstab_entry entry; - - set_info(dev) - set_info(mnt_point) - set_info(type) - set_info(mnt_flags) - set_info(fsmgr_flags) - - fstab.emplace_back(std::move(entry)); - return true; - }); -} - -#define FSR "/first_stage_ramdisk" - -extern uint32_t patch_verity(void *buf, uint32_t size); - -static void append_oplus(vector &fstab) { - LOGD("Found fstab file: oplus.fstab\n"); - map bind_map; - vector entry_list; - - { - // Make sure no duplicate mnt_point exists - set mount_points; - - // Add main fstab entry mnt_points - for (auto &entry: fstab) { - mount_points.emplace(entry.mnt_point); - } - - vector oplus_fstab; - read_fstab_file("oplus.fstab", oplus_fstab); - - for (auto &entry : oplus_fstab) { - if (mount_points.count(entry.mnt_point)) - continue; - if (str_contains(entry.mnt_flags, "bind")) { - bind_map.emplace(std::move(entry.dev), std::move(entry.mnt_point)); - } else { - mount_points.emplace(entry.mnt_point); - entry_list.emplace_back(std::move(entry)); - } - } - } - - for (auto &entry : entry_list) { - // Mount before switch root, fix img path - if (str_starts(entry.dev, "loop@/system/")) - entry.dev.insert(5, "/system_root"); - - // change bind mount entries to dev mount since some users reported bind is not working - // in this case, we drop the original mount point and leave only the one from bind entry - // because some users reported keeping the original mount point causes bootloop - if (auto it = bind_map.find(entry.mnt_point); it != bind_map.end()) { - entry.mnt_point = it->second; - } - - fstab.push_back(std::move(entry)); - } - - unlink("oplus.fstab"); -} - -void FirstStageInit::get_default_fstab(char *buf, size_t len) { - buf[0] = '\0'; - - // Find existing fstab file - for (const char *suffix : { config->fstab_suffix, config->hardware, config->hardware_plat }) { - if (suffix[0] == '\0') - continue; - for (const char *prefix: { "odm/etc/fstab", "vendor/etc/fstab", "system/etc/fstab", "fstab" }) { - snprintf(buf, len, "%s.%s", prefix, suffix); - if (access(buf, F_OK) == 0) { - LOGD("Found fstab file: %s\n", buf); - return; - } - } - } - - buf[0] = '\0'; - - // No existing fstab file is found, create a valid path - const char *suffix = [&]() -> const char * { - if (config->fstab_suffix[0]) - return config->fstab_suffix; - if (config->hardware[0]) - return config->hardware; - if (config->hardware_plat[0]) - return config->hardware_plat; - return nullptr; - }(); - if (suffix == nullptr) { - LOGE("Cannot determine fstab suffix!\n"); - return; - } - snprintf(buf, len, "fstab.%s", suffix); -} +#define INIT_PATH "/system/bin/init" +#define REDIR_PATH "/data/magiskinit" void FirstStageInit::prepare() { - if (is_dsu()) { - rename(backup_init(), "/init"); - LOGI("Skip loading Magisk because of DSU\n"); - return; - } + xmkdirs("/data", 0755); + xmount("tmpfs", "/data", "tmpfs", 0, "mode=755"); + cp_afc("/init" /* magiskinit */, REDIR_PATH); - run_finally finally([]{ chdir("/"); }); - if (config->force_normal_boot) { - xmkdirs(FSR "/system/bin", 0755); - rename("/init" /* magiskinit */, FSR "/system/bin/init"); - symlink("/system/bin/init", FSR "/init"); - rename(backup_init(), "/init"); - - rename("/.backup", FSR "/.backup"); - rename("/overlay.d", FSR "/overlay.d"); - - chdir(FSR); - } else { - xmkdir("/system", 0755); - xmkdir("/system/bin", 0755); - rename("/init" /* magiskinit */ , "/system/bin/init"); - rename(backup_init(), "/init"); - } - - char fstab_file[128]; - get_default_fstab(fstab_file, sizeof(fstab_file)); - - // Empty fstab file path is an error - if (fstab_file[0] == '\0') - return; - - // Try to load dt fstab - vector fstab; - read_dt_fstab(fstab); - - if (!fstab.empty()) { - // Dump dt fstab to fstab file in rootfs and force init to use it instead - - // If there's any error in dt fstab, skip loading it - bool skip = false; - - // All dt fstab entries should be first_stage_mount - for (auto &entry : fstab) { - if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) { - if (!entry.fsmgr_flags.empty()) - entry.fsmgr_flags += ','; - entry.fsmgr_flags += "first_stage_mount"; - } - // If the entry contains slotselect but the current slot is empty, error occurs - if (config->slot[0] == '\0' && str_contains(entry.fsmgr_flags, "slotselect")) { - skip = true; - break; - } // TODO: else if expected_field checks and fs_mgr_flags checks - } - - if (skip) { - // When dt fstab fails, fall back to default fstab - LOGI("dt fstab contains error, fall back to default fstab\n"); - fstab.clear(); - read_fstab_file(fstab_file, fstab); - } else { - // Patch init to force IsDtFstabCompatible() return false - auto init = mmap_data("/init", true); - init.patch({make_pair("android,fstab", "xxx")}); - } - } else { - read_fstab_file(fstab_file, fstab); - } - - // Append oppo's custom fstab - if (access("oplus.fstab", F_OK) == 0) - append_oplus(fstab); + unlink("/init"); + xrename(backup_init(), "/init"); { - LOGD("Write fstab file: %s\n", fstab_file); - auto fp = xopen_file(fstab_file, "we"); - for (auto &entry : fstab) { - // Redirect system mnt_point so init won't switch root in first stage init - if (entry.mnt_point == "/system") - entry.mnt_point = "/system_root"; - - // Force remove AVB for 2SI since it may bootloop some devices - auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length()); - entry.fsmgr_flags.resize(len); - - entry.to_file(fp.get()); - } + auto init = mmap_data("/init", true); + // Redirect original init to magiskinit + init.patch({ make_pair(INIT_PATH, REDIR_PATH) }); } - chmod(fstab_file, 0644); + + // Copy files to tmpfs + cp_afc(".backup", "/data/.backup"); + cp_afc("overlay.d", "/data/overlay.d"); } -#define INIT_PATH "/system/bin/init" -#define REDIR_PATH "/system/bin/am" - void SARInit::first_stage_prep() { - xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755"); + xmount("tmpfs", "/data", "tmpfs", 0, "mode=755"); // Patch init binary int src = xopen("/init", O_RDONLY); - int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0); + int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0); { auto init = mmap_data("/init"); init.patch({ make_pair(INIT_PATH, REDIR_PATH) }); @@ -239,58 +43,35 @@ void SARInit::first_stage_prep() { fclone_attr(src, dest); close(dest); } + xmount("/data/init", "/init", nullptr, MS_BIND, nullptr); // Replace redirect init with magiskinit - dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0); + dest = xopen(REDIR_PATH, O_CREAT | O_WRONLY, 0); write(dest, self.buf, self.sz); fclone_attr(src, dest); close(src); close(dest); - xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr); - xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr); - xumount2("/dev", MNT_DETACH); - - // Block SIGUSR1 - sigset_t block, old; - sigemptyset(&block); - sigaddset(&block, SIGUSR1); - sigprocmask(SIG_BLOCK, &block, &old); - - if (int child = xfork()) { - LOGD("init daemon [%d]\n", child); - // Wait for children signal - int sig; - sigwait(&block, &sig); - - // Restore sigmask - sigprocmask(SIG_SETMASK, &old, nullptr); - } else { - // Establish socket for 2nd stage ack - struct sockaddr_un sun{}; - int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)); - xlisten(sockfd, 1); - - // Resume parent - kill(getppid(), SIGUSR1); - - // Wait for second stage ack - int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC); - - // Write backup files - string tmp_dir = read_string(client); - chdir(tmp_dir.data()); - int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0); - xwrite(cfg, magisk_config.buf, magisk_config.sz); - close(cfg); - restore_folder(ROOTOVL, overlays); - - // Ack and bail out! - write_int(client, 0); - close(client); - close(sockfd); - - exit(0); - } + // Copy files to tmpfs + xmkdir("/data/.backup", 0); + xmkdir("/data/overlay.d", 0); + restore_folder("/data/overlay.d", overlays); + int cfg = xopen("/data/.backup/config", O_WRONLY | O_CREAT, 0); + xwrite(cfg, magisk_config.buf, magisk_config.sz); + close(cfg); +} + +bool SecondStageInit::prepare() { + backup_files(); + + umount2("/init", MNT_DETACH); + umount2("/proc/self/exe", MNT_DETACH); + umount2("/data", MNT_DETACH); + + // Some weird devices like meizu, uses 2SI but still have legacy rootfs + // Check if root and system are on the same filesystem + struct stat root{}, system{}; + xstat("/", &root); + xstat("/system", &system); + return root.st_dev != system.st_dev; }