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);