From 1321f097b823729ba0b2dd99e611098538cb8a73 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 12 Feb 2019 02:14:57 -0500 Subject: [PATCH] Remove usage of magisk.img Mounting ext4 images causes tons of issues, such as unmountable with broken F2FS drivers. Resizing is also very complicated and does not work properly on all devices. Each step in either measuring free space, resizing, and shrinking the image is a point of failure, and either step's failure could cause the module system completely broken. The new method is to directly store modules into /data/adb/modules, and for module installation on boot /data/adb/modules_update. Several compatibility layers has been done: the new path is bind mounted to the old path (/sbin/.magisk/img), and the helper functions in util_functions.sh will now transparently make existing modules install to the new location without any changes. MagiskHide is also updated to unmount module files stored in this new location. --- native/jni/core/bootstages.cpp | 123 +++++++++++-------------- native/jni/include/magisk.h | 8 +- native/jni/magiskhide/hide_utils.cpp | 2 +- native/jni/magiskhide/proc_monitor.cpp | 6 +- native/jni/utils/selinux.cpp | 3 +- scripts/util_functions.sh | 67 ++++---------- 6 files changed, 84 insertions(+), 125 deletions(-) diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index c04d770be..e0bd27921 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -19,12 +19,11 @@ #include #include #include -#include #include #include #include -#include #include +#include using namespace std; @@ -32,7 +31,7 @@ static char buf[PATH_MAX], buf2[PATH_MAX]; static vector module_list; static bool seperate_vendor; -char *system_block, *vendor_block, *magiskloop; +char *system_block, *vendor_block, *data_block; static int bind_mount(const char *from, const char *to); extern void auto_start_magiskhide(); @@ -135,7 +134,7 @@ void node_entry::create_module_tree(const char *module) { struct dirent *entry; auto full_path = get_path(); - snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, full_path.c_str()); + snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, full_path.c_str()); if (!(dir = xopendir(buf))) return; @@ -169,7 +168,7 @@ void node_entry::create_module_tree(const char *module) { node->status = IS_MODULE; } else if (IS_DIR(node)) { // Check if marked as replace - snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf); + snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MODULEROOT, module, buf); if (access(buf2, F_OK) == 0) { // Replace everything, mark as leaf node->status = IS_MODULE; @@ -236,7 +235,7 @@ void node_entry::clone_skeleton() { continue; } else if (child->status & IS_MODULE) { // Mount from module file to dummy file - snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, + snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MODULEROOT, child->module, full_path.c_str(), child->name.c_str()); } else if (child->status & (IS_SKEL | IS_INTER)) { // It's an intermediate folder, recursive clone @@ -262,7 +261,7 @@ void node_entry::magic_mount() { if (status & IS_MODULE) { // Mount module item auto real_path = get_path(); - snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, real_path.c_str()); + snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, real_path.c_str()); bind_mount(buf, real_path.c_str()); } else if (status & IS_SKEL) { // The node is labeled to be cloned with skeleton, lets do it @@ -338,7 +337,7 @@ static void exec_common_script(const char* stage) { static void exec_module_script(const char* stage) { for (const auto &m : module_list) { const auto module = m.c_str(); - snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage); + snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MODULEROOT, module, stage); if (access(buf2, F_OK) == -1) continue; LOGI("%s: exec [%s.sh]\n", module, stage); @@ -418,18 +417,21 @@ static bool magisk_env() { // Remove legacy stuffs unlink("/data/magisk.img"); unlink("/data/magisk_debug.log"); + unlink(SECURE_DIR "/magisk.img"); + unlink(SECURE_DIR "/magisk_merge.img"); - // Symlink for legacy path users + // Legacy support symlink(MAGISKTMP, "/sbin/.core"); + xmkdir(MAGISKTMP "/img", 0755); // Create directories in tmpfs overlay xmkdirs(MIRRDIR "/system", 0755); xmkdir(MIRRDIR "/bin", 0755); xmkdir(BBPATH, 0755); - xmkdir(MOUNTPOINT, 0755); xmkdir(BLOCKDIR, 0755); - // Boot script directories + // /data/adb directories + xmkdir(MODULEROOT, 0755); xmkdir(SECURE_DIR "/post-fs-data.d", 0755); xmkdir(SECURE_DIR "/service.d", 0755); @@ -454,6 +456,9 @@ static bool magisk_env() { xmkdir(MIRRDIR "/vendor", 0755); xmount(vendor_block, MIRRDIR "/vendor", buf2, MS_RDONLY, nullptr); VLOGI("mount", vendor_block, MIRRDIR "/vendor"); + } else if (str_contains(line, " /data ")) { + sscanf(line.c_str(), "%s", buf); + data_block = strdup(buf); } else if (SDK_INT >= 24 && str_contains(line, " /proc ") && !str_contains(line, "hidepid=2")) { // Enforce hidepid @@ -482,16 +487,43 @@ static bool magisk_env() { return true; } +static void upgrade_modules() { + DIR *dir; + struct dirent *entry; + if ((dir = opendir(MODULEUPGRADE))) { + while ((entry = xreaddir(dir))) { + if (entry->d_type == DT_DIR) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + // Cleanup old module if exists + snprintf(buf, sizeof(buf), "%s/%s", MODULEROOT, entry->d_name); + if (access(buf, F_OK) == 0) + rm_rf(buf); + LOGI("Upgrade / New module: %s\n", entry->d_name); + snprintf(buf2, sizeof(buf2), "%s/%s", MODULEUPGRADE, entry->d_name); + rename(buf2, buf); + } + } + closedir(dir); + rm_rf(MODULEUPGRADE); + } + // Legacy support + bind_mount(MODULEROOT, MAGISKTMP "/img"); + xmkdir(LEGACYCORE, 0755); + symlink(SECURE_DIR "/post-fs-data.d", LEGACYCORE "/post-fs-data.d"); + symlink(SECURE_DIR "/service.d", LEGACYCORE "/service.d"); +} + static void collect_modules() { - chdir(MOUNTPOINT); + chdir(MODULEROOT); + rm_rf("lost+found"); DIR *dir = xopendir("."); struct dirent *entry; while ((entry = xreaddir(dir))) { if (entry->d_type == DT_DIR) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || - strcmp(entry->d_name, ".core") == 0 || - strcmp(entry->d_name, "lost+found") == 0) + strcmp(entry->d_name, ".core") == 0) continue; chdir(entry->d_name); if (access("remove", F_OK) == 0) { @@ -510,47 +542,6 @@ static void collect_modules() { chdir("/"); } -static bool prepare_img() { - const char *alt_img[] = - { "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img" }; - - for (auto &alt : alt_img) { - if (merge_img(alt, MAINIMG)) { - LOGE("Image merge %s -> " MAINIMG " failed!\n", alt); - return false; - } - } - - if (access(MAINIMG, F_OK) == -1) { - if (create_img(MAINIMG, 64)) - return false; - } - - LOGI("* Mounting " MAINIMG "\n"); - magiskloop = mount_image(MAINIMG, MOUNTPOINT); - if (magiskloop == nullptr) - return false; - - // Migrate legacy boot scripts - struct stat st; - if (lstat(LEGACY_CORE "/post-fs-data.d", &st) == 0 && S_ISDIR(st.st_mode)) { - cp_afc(LEGACY_CORE "/post-fs-data.d", SECURE_DIR "/post-fs-data.d"); - rm_rf(LEGACY_CORE "/post-fs-data.d"); - } - if (lstat(LEGACY_CORE "/service.d", &st) == 0 && S_ISDIR(st.st_mode)) { - cp_afc(LEGACY_CORE "/service.d", SECURE_DIR "/service.d"); - rm_rf(LEGACY_CORE "/service.d"); - } - - // Links for legacy paths - xmkdir(LEGACY_CORE, 0755); - symlink(SECURE_DIR "/post-fs-data.d", LEGACY_CORE "/post-fs-data.d"); - symlink(SECURE_DIR "/service.d", LEGACY_CORE "/service.d"); - - collect_modules(); - return trim_img(MAINIMG, MOUNTPOINT, magiskloop) == 0; -} - static void install_apk(const char *apk) { setfilecon(apk, "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); while (true) { @@ -688,24 +679,20 @@ void post_fs_data(int client) { start_logcat(); - // Run common scripts LOGI("* Running post-fs-data.d scripts\n"); exec_common_script("post-fs-data"); + upgrade_modules(); + // Core only mode if (access(DISABLEFILE, F_OK) == 0) core_only(); - if (!prepare_img()) { - LOGE("* Magisk image mount failed, switch to core-only mode\n"); - free(magiskloop); - magiskloop = nullptr; - creat(DISABLEFILE, 0644); - } - restorecon(); chmod(SECURE_DIR, 0700); + collect_modules(); + // Execute module scripts LOGI("* Running module post-fs-data scripts\n"); exec_module_script("post-fs-data"); @@ -726,17 +713,17 @@ void post_fs_data(int client) { for (const auto &m : module_list) { const auto module = m.c_str(); // Read props - snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module); + snprintf(buf, PATH_MAX, "%s/%s/system.prop", MODULEROOT, module); if (access(buf, F_OK) == 0) { LOGI("%s: loading [system.prop]\n", module); load_prop_file(buf, false); } // Check whether enable auto_mount - snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module); + snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MODULEROOT, module); if (access(buf, F_OK) == -1) continue; // Double check whether the system folder exists - snprintf(buf, PATH_MAX, "%s/%s/system", MOUNTPOINT, module); + snprintf(buf, PATH_MAX, "%s/%s/system", MODULEROOT, module); if (access(buf, F_OK) == -1) continue; @@ -744,9 +731,9 @@ void post_fs_data(int client) { has_modules = true; LOGI("%s: constructing magic mount structure\n", module); // If /system/vendor exists in module, create a link outside - snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module); + snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MODULEROOT, module); if (access(buf, F_OK) == 0) { - snprintf(buf2, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, module); + snprintf(buf2, PATH_MAX, "%s/%s/vendor", MODULEROOT, module); unlink(buf2); xsymlink(buf, buf2); } diff --git a/native/jni/include/magisk.h b/native/jni/include/magisk.h index 48fcb45d7..1ff30d2c9 100644 --- a/native/jni/include/magisk.h +++ b/native/jni/include/magisk.h @@ -18,16 +18,18 @@ #define BLOCKDIR MAGISKTMP "/block" #define MIRRDIR MAGISKTMP "/mirror" #define BBPATH MAGISKTMP "/busybox" -#define MOUNTPOINT MAGISKTMP "/img" -#define LEGACY_CORE MOUNTPOINT "/.core" #define SECURE_DIR "/data/adb" -#define MAINIMG SECURE_DIR "/magisk.img" +#define MODULEROOT SECURE_DIR "/modules" +#define MODULEUPGRADE SECURE_DIR "/modules_update" #define DATABIN SECURE_DIR "/magisk" #define MAGISKDB SECURE_DIR "/magisk.db" #define SIMPLEMOUNT SECURE_DIR "/magisk_simple" #define BOOTCOUNT SECURE_DIR "/.boot_count" #define MANAGERAPK DATABIN "/magisk.apk" +// Legacy crap +#define LEGACYCORE MODULEROOT "/.core" + // selinux consts #define SELINUX_PATH "/sys/fs/selinux" #define SELINUX_ENFORCE SELINUX_PATH "/enforce" diff --git a/native/jni/magiskhide/hide_utils.cpp b/native/jni/magiskhide/hide_utils.cpp index c6234e362..c9b16529c 100644 --- a/native/jni/magiskhide/hide_utils.cpp +++ b/native/jni/magiskhide/hide_utils.cpp @@ -233,7 +233,7 @@ int rm_list(int client) { return ret; } -#define LEGACY_LIST MOUNTPOINT "/.core/hidelist" +#define LEGACY_LIST MODULEROOT "/.core/hidelist" static int collect_list(void *, int, char **data, char**) { LOGI("hide_list: [%s]\n", data[0]); diff --git a/native/jni/magiskhide/proc_monitor.cpp b/native/jni/magiskhide/proc_monitor.cpp index c226aae0d..98b29d217 100644 --- a/native/jni/magiskhide/proc_monitor.cpp +++ b/native/jni/magiskhide/proc_monitor.cpp @@ -26,7 +26,7 @@ using namespace std; -extern char *system_block, *vendor_block, *magiskloop; +extern char *system_block, *vendor_block, *data_block; // Workaround for the lack of pthread_cancel static void term_thread(int) { @@ -91,10 +91,10 @@ static void hide_daemon(int pid) { // Re-read mount infos mounts = file_to_vector("mounts"); - // Unmount everything under /system, /vendor, and loop mounts + // Unmount everything under /system, /vendor, and data mounts for (auto &s : mounts) { if ((str_contains(s, " /system/") || str_contains(s, " /vendor/")) && - (str_contains(s, system_block) || str_contains(s, vendor_block) || str_contains(s, magiskloop))) { + (str_contains(s, system_block) || str_contains(s, vendor_block) || str_contains(s, data_block))) { sscanf(s.c_str(), "%*s %4096s", buffer); lazy_unmount(buffer); } diff --git a/native/jni/utils/selinux.cpp b/native/jni/utils/selinux.cpp index 9a38473b5..d695f6fea 100644 --- a/native/jni/utils/selinux.cpp +++ b/native/jni/utils/selinux.cpp @@ -162,7 +162,8 @@ void restorecon() { if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0) lsetfilecon(SECURE_DIR, ADB_CON); close(fd); - fd = xopen(MOUNTPOINT, O_RDONLY | O_CLOEXEC); + lsetfilecon(MODULEROOT, MAGISK_CON); + fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC); restore_syscon(fd); close(fd); fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC); diff --git a/scripts/util_functions.sh b/scripts/util_functions.sh index a60c4f2b5..f107f62a2 100644 --- a/scripts/util_functions.sh +++ b/scripts/util_functions.sh @@ -52,7 +52,8 @@ abort() { resolve_vars() { MAGISKBIN=$NVBASE/magisk - IMG=$NVBASE/magisk.img + POSTFSDATAD=$NVBASE/post-fs-data.d + SERVICED=$NVBASE/service.d } ###################### @@ -351,7 +352,9 @@ find_manager_apk() { set_perm() { chown $2:$3 $1 || return 1 chmod $4 $1 || return 1 - [ -z $5 ] && chcon 'u:object_r:system_file:s0' $1 || chcon $5 $1 || return 1 + CON=$5 + [ -z $CON ] && CON=u:object_r:system_file:s0 + chcon $CON $1 || return 1 } set_perm_recursive() { @@ -370,64 +373,30 @@ mktouch() { } request_size_check() { - reqSizeM=`du -ms $1 | cut -f1` + reqSizeM=`du -ms "$1" | cut -f1` } request_zip_size_check() { reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'` } -check_filesystem() { - curSizeM=`wc -c < $1` - curSizeM=$((curSizeM / 1048576)) - local DF=`df -Pk $2 | grep $2` - curUsedM=`echo $DF | awk '{ print int($3 / 1024) }'` - curFreeM=`echo $DF | awk '{ print int($4 / 1024) }'` -} - -mount_snippet() { - MAGISKLOOP=`$MAGISKBIN/magisk imgtool mount $IMG $MOUNTPATH` - is_mounted $MOUNTPATH || abort "! $IMG mount failed..." -} - -mount_magisk_img() { - [ -z $reqSizeM ] && reqSizeM=0 - mkdir -p $MOUNTPATH 2>/dev/null - if [ -f "$IMG" ]; then - ui_print "- Found $IMG" - mount_snippet - check_filesystem $IMG $MOUNTPATH - if [ $reqSizeM -gt $curFreeM ]; then - newSizeM=$(((curSizeM + reqSizeM - curFreeM) / 32 * 32 + 64)) - ui_print "- Resizing $IMG to ${newSizeM}M" - $MAGISKBIN/magisk imgtool umount $MOUNTPATH $MAGISKLOOP - $MAGISKBIN/magisk imgtool resize $IMG $newSizeM >&2 - mount_snippet - fi - ui_print "- Mount $IMG to $MOUNTPATH" - else - newSizeM=$((reqSizeM / 32 * 32 + 64)) - ui_print "- Creating $IMG with size ${newSizeM}M" - $MAGISKBIN/magisk imgtool create $IMG $newSizeM >&2 - mount_snippet - fi -} - -unmount_magisk_img() { - check_filesystem $IMG $MOUNTPATH - newSizeM=$((curUsedM / 32 * 32 + 64)) - $MAGISKBIN/magisk imgtool umount $MOUNTPATH $MAGISKLOOP - if [ $curSizeM -gt $newSizeM ]; then - ui_print "- Shrinking $IMG to ${newSizeM}M" - $MAGISKBIN/magisk imgtool resize $IMG $newSizeM >&2 - fi -} - ################################## # Backwards Compatibile Functions ################################## + get_outfd() { setup_flashable; } +mount_magisk_img() { + $BOOTMODE && MODULE_BASE=modules_update || MODULE_BASE=modules + MODULEPATH=$NVBASE/$MODULE_BASE + mkdir -p $MODULEPATH 2>/dev/null + ln -s $MODULEPATH $MOUNTPATH +} + +unmount_magisk_img() { + rm -f $MODULEPATH 2>/dev/null +} + ####### # main #######