From 92b305a389bcb0dc7e2b3169134f0a81bac6c513 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Fri, 5 Jan 2024 00:42:33 +0800 Subject: [PATCH] Remove unnecessary mirror for magic mount Mirror was previously used for accessing the original file during magic mount when we are using a tmpfs to cover the target. However, since we introduce atomic mount, we switch all tmpfs mount in worker and then move to the target at once. It means that we can still access the original file when we are constructing the tmpfs mount point. Thus we no longer need mirror. --- native/src/core/bootstages.cpp | 50 +++++----------------------------- native/src/core/module.cpp | 48 ++++++++++++-------------------- native/src/core/node.hpp | 35 ++++++++++-------------- 3 files changed, 40 insertions(+), 93 deletions(-) diff --git a/native/src/core/bootstages.cpp b/native/src/core/bootstages.cpp index 20b99b6ab..4ba394389 100644 --- a/native/src/core/bootstages.cpp +++ b/native/src/core/bootstages.cpp @@ -19,18 +19,10 @@ bool zygisk_enabled = false; /********* * Setup * *********/ - -static bool rec_mount(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); -} - -static void mount_mirrors() { - LOGI("* Mounting mirrors\n"); +static void setup_mounts() { + LOGI("* Magic mount setup\n"); auto self_mount_info = parse_mount_info("self"); - char path[64]; + char path[PATH_MAX]; // Bind remount module root to clear nosuid if (access(SECURE_DIR, F_OK) == 0 || SDK_INT < 24) { @@ -65,8 +57,9 @@ static void mount_mirrors() { if (!rw) continue; string preinit_dir = resolve_preinit_dir(info.target.data()); xmkdir(preinit_dir.data(), 0700); - if ((mounted = rec_mount(preinit_dir, path))) { - xmount(nullptr, path, nullptr, MS_UNBINDABLE, nullptr); + xmkdirs(path, 0755); + mounted = xmount(preinit_dir.data(), path, nullptr, MS_BIND, nullptr) == 0; + if (mounted) { break; } } @@ -81,27 +74,6 @@ static void mount_mirrors() { ssprintf(path, sizeof(path), "%s/" WORKERDIR, get_magisk_tmp()); xmount("worker", path, "tmpfs", 0, "mode=755"); xmount(nullptr, path, nullptr, MS_PRIVATE, nullptr); - // Recursively bind mount / to mirror dir - // Keep mirror shared so that mounting during post-fs-data will be propagated - if (auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR; !rec_mount("/", mirror_dir)) { - LOGI("fallback to mount subtree\n"); - // create new a bind mount for easy make private - xmount(mirror_dir.data(), mirror_dir.data(), nullptr, MS_BIND, nullptr); - // rootfs may fail, fallback to bind mount each mount point - set> mounted_dirs {{ get_magisk_tmp() }}; - for (const auto &info: self_mount_info) { - if (info.type == "rootfs"sv) continue; - // the greatest mount point that less than info.target, which is possibly a parent - if (auto last_mount = mounted_dirs.upper_bound(info.target); - last_mount != mounted_dirs.end() && info.target.starts_with(*last_mount + '/')) { - continue; - } - if (rec_mount(info.target, mirror_dir + info.target)) { - LOGD("%-8s: %s <- %s\n", "rbind", (mirror_dir + info.target).data(), info.target.data()); - mounted_dirs.insert(info.target); - } - } - } } string find_preinit_device() { @@ -310,7 +282,7 @@ bool MagiskD::post_fs_data() const { LOGI("** post-fs-data mode running\n"); unlock_blocks(); - mount_mirrors(); + setup_mounts(); prune_su_access(); bool safe_mode = false; @@ -341,15 +313,7 @@ bool MagiskD::post_fs_data() const { } early_abort: - auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR; - // make mirror dir as a private mount so that it won't be affected by magic mount - LOGD("make %s private\n", mirror_dir.data()); - xmount(nullptr, mirror_dir.data(), nullptr, MS_PRIVATE | MS_REC, nullptr); - // We still do magic mount because root itself might need it load_modules(); - // make mirror dir as a shared mount to make magisk --stop work for other ns - xmount(nullptr, mirror_dir.data(), nullptr, MS_SHARED | MS_REC, nullptr); - LOGD("make %s shared\n", mirror_dir.data()); return safe_mode; } diff --git a/native/src/core/module.cpp b/native/src/core/module.cpp index cd77c6557..64c9328c1 100644 --- a/native/src/core/module.cpp +++ b/native/src/core/module.cpp @@ -27,24 +27,18 @@ static int bind_mount(const char *reason, const char *from, const char *to) { *************************/ tmpfs_node::tmpfs_node(node_entry *node) : dir_node(node, this) { - if (!skip_mirror()) { - string mirror = mirror_path(); - if (auto dir = open_dir(mirror.data())) { + if (!replace()) { + if (auto dir = open_dir(node_path().data())) { set_exist(true); for (dirent *entry; (entry = xreaddir(dir.get()));) { - if (entry->d_type == DT_DIR) { - // create a dummy inter_node to upgrade later - emplace(entry->d_name, entry->d_name); - } else { - // Insert mirror nodes - emplace(entry->d_name, entry); - } + // create a dummy inter_node to upgrade later + emplace(entry->d_name, entry); } } } for (auto it = children.begin(); it != children.end(); ++it) { - // Need to upgrade all inter_node children to tmpfs_node + // Upgrade resting inter_node children to tmpfs_node if (isa(it->second)) it = upgrade(it); } @@ -52,7 +46,7 @@ tmpfs_node::tmpfs_node(node_entry *node) : dir_node(node, this) { bool dir_node::prepare() { // If direct replace or not exist, mount ourselves as tmpfs - bool upgrade_to_tmpfs = skip_mirror() || !exist(); + bool upgrade_to_tmpfs = replace() || !exist(); for (auto it = children.begin(); it != children.end();) { // We also need to upgrade to tmpfs node if any child: @@ -77,9 +71,9 @@ bool dir_node::prepare() { upgrade_to_tmpfs = true; } if (auto dn = dyn_cast(it->second)) { - if (skip_mirror()) { + if (replace()) { // Propagate skip mirror state to all children - dn->set_skip_mirror(true); + dn->set_replace(true); } if (dn->prepare()) { // Upgrade child to tmpfs @@ -98,7 +92,7 @@ void dir_node::collect_module_files(const char *module, int dfd) { for (dirent *entry; (entry = xreaddir(dir.get()));) { if (entry->d_name == ".replace"sv) { - set_skip_mirror(true); + set_replace(true); continue; } @@ -141,18 +135,12 @@ void node_entry::create_and_mount(const char *reason, const string &src, bool ro } } -void mirror_node::mount() { - create_and_mount("mirror", mirror_path()); -} - void module_node::mount() { std::string path = module + (parent()->root()->prefix + node_path()); string mnt_src = module_mnt + path; { string src = MODULEROOT "/" + path; - if (exist()) clone_attr(mirror_path().data(), src.data()); - // special case for /system/etc/hosts to ensure it is writable - if (node_path() == "/system/etc/hosts") mnt_src = std::move(src); + if (exist()) clone_attr(node_path().data(), src.data()); } if (isa(parent())) { create_and_mount("module", mnt_src); @@ -162,22 +150,23 @@ void module_node::mount() { } void tmpfs_node::mount() { - string src = mirror_path(); - const char *src_path = access(src.data(), F_OK) == 0 ? src.data() : nullptr; + if (!is_dir()) { + create_and_mount("mirror", node_path()); + return; + } if (!isa(parent())) { - const string &dest = node_path(); auto worker_dir = worker_path(); mkdirs(worker_dir.data(), 0); bind_mount("tmpfs", worker_dir.data(), worker_dir.data()); - clone_attr(src_path ?: parent()->node_path().data(), worker_dir.data()); + clone_attr(exist() ? node_path().data() : parent()->node_path().data(), worker_dir.data()); dir_node::mount(); - VLOGD(skip_mirror() ? "replace" : "move", worker_dir.data(), dest.data()); - xmount(worker_dir.data(), dest.data(), nullptr, MS_MOVE, nullptr); + VLOGD(replace() ? "replace" : "move", worker_dir.data(), node_path().data()); + xmount(worker_dir.data(), node_path().data(), nullptr, MS_MOVE, nullptr); } else { const string dest = worker_path(); // We don't need another layer of tmpfs if parent is tmpfs mkdir(dest.data(), 0); - clone_attr(src_path ?: parent()->worker_path().data(), dest.data()); + clone_attr(exist() ? node_path().data() : parent()->worker_path().data(), dest.data()); dir_node::mount(); } } @@ -265,7 +254,6 @@ static void inject_zygisk_libs(root_node *system) { vector *module_list; void load_modules() { - node_entry::mirror_dir = get_magisk_tmp() + "/"s MIRRDIR; node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/"; auto root = make_unique(""); diff --git a/native/src/core/node.hpp b/native/src/core/node.hpp index f0969cc49..b34d40b91 100644 --- a/native/src/core/node.hpp +++ b/native/src/core/node.hpp @@ -5,18 +5,16 @@ using namespace std; -#define TYPE_MIRROR (1 << 0) /* mount from mirror */ -#define TYPE_INTER (1 << 1) /* intermediate node */ -#define TYPE_TMPFS (1 << 2) /* replace with tmpfs */ -#define TYPE_MODULE (1 << 3) /* mount from module */ -#define TYPE_ROOT (1 << 4) /* partition root */ -#define TYPE_CUSTOM (1 << 5) /* custom node type overrides all */ +#define TYPE_INTER (1 << 0) /* intermediate node */ +#define TYPE_TMPFS (1 << 1) /* replace with tmpfs */ +#define TYPE_MODULE (1 << 2) /* mount from module */ +#define TYPE_ROOT (1 << 3) /* partition root */ +#define TYPE_CUSTOM (1 << 4) /* custom node type overrides all */ #define TYPE_DIR (TYPE_INTER|TYPE_TMPFS|TYPE_ROOT) class node_entry; class dir_node; class inter_node; -class mirror_node; class tmpfs_node; class module_node; class root_node; @@ -27,7 +25,6 @@ template static T *dyn_cast(node_entry *node); template uint8_t type_id() { return TYPE_CUSTOM; } template<> uint8_t type_id() { return TYPE_DIR; } template<> uint8_t type_id() { return TYPE_INTER; } -template<> uint8_t type_id() { return TYPE_MIRROR; } template<> uint8_t type_id() { return TYPE_TMPFS; } template<> uint8_t type_id() { return TYPE_MODULE; } template<> uint8_t type_id() { return TYPE_ROOT; } @@ -47,12 +44,9 @@ public: const string &node_path(); const string worker_path(); - string mirror_path() { return mirror_dir + node_path(); } - virtual void mount() = 0; inline static string module_mnt; - inline static string mirror_dir; protected: template @@ -174,6 +168,12 @@ protected: _root = self; } + template + dir_node(dirent *entry, T *self) : node_entry(entry->d_name, entry->d_type, self) { + if constexpr (std::is_same_v) + _root = self; + } + template dir_node(node_entry *node, T *self) : node_entry(self) { if constexpr (std::is_same_v) @@ -192,8 +192,8 @@ protected: // Use bit 6 of _file_type // Skip binding mirror for this directory - bool skip_mirror() const { return static_cast(_file_type & (1 << 6)); } - void set_skip_mirror(bool b) { if (b) _file_type |= (1 << 6); else _file_type &= ~(1 << 6); } + bool replace() const { return static_cast(_file_type & (1 << 6)); } + void set_replace(bool b) { if (b) _file_type |= (1 << 6); else _file_type &= ~(1 << 6); } template T *iterator_to_node(iterator it) { @@ -273,6 +273,7 @@ public: class inter_node : public dir_node { public: inter_node(const char *name) : dir_node(name, this) {} + inter_node(dirent *entry) : dir_node(entry, this) {} }; class module_node : public node_entry { @@ -289,13 +290,7 @@ private: const char *module; }; -// Don't create the following two nodes before prepare -class mirror_node : public node_entry { -public: - explicit mirror_node(dirent *entry) : node_entry(entry->d_name, entry->d_type, this) {} - void mount() override; -}; - +// Don't create tmpfs_node before prepare class tmpfs_node : public dir_node { public: explicit tmpfs_node(node_entry *node);