diff --git a/docs/guides.md b/docs/guides.md index b13134a84..d2ea10719 100644 --- a/docs/guides.md +++ b/docs/guides.md @@ -120,7 +120,7 @@ All files you want to replace/inject should be placed in this folder. This folde If you place a file named `.replace` in any of the folders, instead of merging its contents, that folder will directly replace the one in the real system. This can be very handy for swapping out an entire folder. -If you want to replace files in `/vendor`, `/product`, or `/system_ext`, please place them under `system/vendor`, `system/product`, and `system/system_ext` respectively. Magisk will transparently handle whether these partitions are in a separate partition or not. +If you want to replace files in `/vendor`, `/vendor_dlkm`, `/product`, `/system_ext`, `/system_dlkm`, `/odm`, or `/odm_dlkm`, please place them under `system/vendor`, `system/product`, and `system/system_ext` respectively. Magisk will transparently handle whether these partitions are in a separate partition or not. #### Zygisk diff --git a/native/src/core/bootstages.cpp b/native/src/core/bootstages.cpp index 4bb4f596b..935599c19 100644 --- a/native/src/core/bootstages.cpp +++ b/native/src/core/bootstages.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -34,103 +35,60 @@ bool zygisk_enabled = false; * Setup * *********/ -#define MNT_DIR_IS(dir) (me->mnt_dir == string_view(dir)) -#define MNT_TYPE_IS(type) (me->mnt_type == string_view(type)) -#define SETMIR(b, part) ssprintf(b, sizeof(b), "%s/" MIRRDIR "/" #part, MAGISKTMP.data()) -#define SETBLK(b, part) ssprintf(b, sizeof(b), "%s/" BLOCKDIR "/" #part, MAGISKTMP.data()) - -#define do_mount_mirror(part) { \ - SETMIR(buf1, part); \ - SETBLK(buf2, part); \ - unlink(buf2); \ - mknod(buf2, S_IFBLK | 0600, st.st_dev); \ - xmkdir(buf1, 0755); \ - int flags = 0; \ - auto opts = split_ro(me->mnt_opts, ",");\ - for (string_view s : opts) { \ - if (s == "ro") { \ - flags |= MS_RDONLY; \ - break; \ - } \ - } \ - xmount(buf2, buf1, me->mnt_type, flags, nullptr); \ - LOGI("mount: %s\n", buf1); \ +static bool mount_mirror(const std::string_view from, const std::string_view to) { + return !xmkdirs(to.data(), 0755) && + // recursively bind mount to mirror dir, rootfs will fail before 3.12 kernel + // because of MS_NOUSER + !mount(from.data(), to.data(), nullptr, MS_BIND | MS_REC, nullptr) && + // make mirror dir as a private mount so that it won't be affected by magic mount + !xmount("", to.data(), nullptr, MS_PRIVATE | MS_REC, nullptr); } -#define mount_mirror(part) \ -if (MNT_DIR_IS("/" #part) \ - && !MNT_TYPE_IS("tmpfs") \ - && !MNT_TYPE_IS("overlay") \ - && lstat(me->mnt_dir, &st) == 0) { \ - do_mount_mirror(part); \ - break; \ -} - -#define link_mirror(part) \ -SETMIR(buf1, part); \ -if (access("/system/" #part, F_OK) == 0 && access(buf1, F_OK) != 0) { \ - xsymlink("./system/" #part, buf1); \ - LOGI("link: %s\n", buf1); \ -} - -#define link_orig_dir(dir, part) \ -if (MNT_DIR_IS(dir) && !MNT_TYPE_IS("tmpfs") && !MNT_TYPE_IS("overlay")) { \ - SETMIR(buf1, part); \ - rmdir(buf1); \ - xsymlink(dir, buf1); \ - LOGI("link: %s\n", buf1); \ - break; \ -} - -#define link_orig(part) link_orig_dir("/" #part, part) - static void mount_mirrors() { - char buf1[4096]; - char buf2[4096]; - LOGI("* Prepare worker\n"); - - ssprintf(buf1, sizeof(buf1), "%s/" WORKERDIR, MAGISKTMP.data()); - xmount(buf1, buf1, nullptr, MS_BIND, nullptr); - xmount(nullptr, buf1, nullptr, MS_PRIVATE, nullptr); + if (auto worker_dir = MAGISKTMP + "/" WORKERDIR; + xmount(worker_dir.data(), worker_dir.data(), nullptr, MS_BIND, nullptr) == 0) { + xmount(nullptr, worker_dir.data(), nullptr, MS_PRIVATE, nullptr); + } LOGI("* Mounting mirrors\n"); + // recursively bind mount / to mirror dir + if (auto mirror_dir = MAGISKTMP + "/" MIRRDIR; !mount_mirror("/", mirror_dir)) { + LOGI("fallback to mount subtree\n"); + // rootfs may fail, fallback to bind mount each mount point + std::vector mounted_dirs {{ MAGISKTMP }}; + for (const auto &info: parse_mount_info("self")) { + if (info.type == "rootfs"sv) continue; + bool mounted = std::any_of(mounted_dirs.begin(), mounted_dirs.end(), [&](const auto &dir) { + return str_starts(info.target, dir); + }); + if (!mounted && mount_mirror(info.target, mirror_dir + info.target)) { + mounted_dirs.emplace_back(info.target); + } + } + } - parse_mnt("/proc/mounts", [&](mntent *me) { - struct stat st{}; - do { - mount_mirror(system) - mount_mirror(vendor) - mount_mirror(product) - mount_mirror(system_ext) - mount_mirror(data) - link_orig(cache) - link_orig(metadata) - link_orig(persist) - link_orig_dir("/mnt/vendor/persist", persist) - if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) { - xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009"); + LOGI("* Mounting module root\n"); + if (access(SECURE_DIR, F_OK) == 0 || (SDK_INT < 24 && xmkdir(SECURE_DIR, 0700))) { + if (auto dest = MAGISKTMP + "/" MODULEMNT; mount_mirror(MODULEROOT, dest)) { + // remount to clear nosuid flag + struct statvfs st{}; + statvfs(dest.data(), &st); + for (const auto &info: parse_mount_info("self")) { + if (info.target != dest) { + continue; + } + // strip rw, from fs options + if (auto pos = info.fs_option.find_first_of(','); pos != string::npos) { + xmount("", dest.data(), nullptr, MS_REMOUNT | (st.f_flag & ~MS_NOSUID), info.fs_option.data() + pos + 1); + } break; } - } while (false); - return true; - }); - SETMIR(buf1, system); - if (access(buf1, F_OK) != 0) { - xsymlink("./system_root/system", buf1); - LOGI("link: %s\n", buf1); - parse_mnt("/proc/mounts", [&](mntent *me) { - struct stat st; - if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) { - do_mount_mirror(system_root) - return false; - } - return true; - }); + restorecon(); + chmod(SECURE_DIR, 0700); + } } - link_mirror(vendor) - link_mirror(product) - link_mirror(system_ext) + } static bool magisk_env() { @@ -306,16 +264,8 @@ static void post_fs_data() { prune_su_access(); if (access(SECURE_DIR, F_OK) != 0) { - if (SDK_INT < 24) { - // There is no FBE pre 7.0, we can directly create the folder without issues - xmkdir(SECURE_DIR, 0700); - } else { - // If the folder is not automatically created by Android, - // do NOT proceed further. Manual creation of the folder - // will have no encryption flag, which will cause bootloops on FBE devices. - LOGE(SECURE_DIR " is not present, abort\n"); - goto early_abort; - } + LOGE(SECURE_DIR " is not present, abort\n"); + goto early_abort; } if (!magisk_env()) { diff --git a/native/src/core/module.cpp b/native/src/core/module.cpp index aa38db99c..acd16804a 100644 --- a/native/src/core/module.cpp +++ b/native/src/core/module.cpp @@ -32,7 +32,7 @@ class root_node; template static bool isa(node_entry *node); static int bind_mount(const char *reason, const char *from, const char *to) { - int ret = xmount(from, to, nullptr, MS_BIND, nullptr); + int ret = xmount(from, to, nullptr, MS_BIND | MS_REC, nullptr); if (ret == 0) VLOGD(reason, from, to); return ret; @@ -623,7 +623,9 @@ void magic_mount() { if (!system->is_empty()) { // Handle special read-only partitions - for (const char *part : { "/vendor", "/product", "/system_ext" }) { + for (const char *part : { "/vendor", "/vendor_dlkm","/product", + "/system_ext", "/system_dlkm", + "/odm", "/odm_dlkm" }) { struct stat st{}; if (lstat(part, &st) == 0 && S_ISDIR(st.st_mode)) { if (auto old = system->extract(part + 1)) { @@ -669,15 +671,6 @@ static void prepare_modules() { close(mfd); rm_rf(MODULEUPGRADE); } - - // Setup module mount (workaround nosuid selabel issue) - auto src = MAGISKTMP + "/" MIRRDIR MODULEROOT; - auto dest = MAGISKTMP + "/" MODULEMNT; - xmkdir(dest.data(), 0755); - bind_mount("mod_mnt", src.data(), dest.data()); - - restorecon(); - chmod(SECURE_DIR, 0700); } template