From 79a85f5937f5a49b75de0326ed366e5f36ed7463 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 27 Dec 2022 02:01:45 +0800 Subject: [PATCH] Use mountinfo for revert unmount --- native/src/base/files.cpp | 82 +++++++++++++++++++++++++++++++ native/src/base/files.hpp | 18 +++++++ native/src/zygisk/deny/revert.cpp | 29 ++++------- 3 files changed, 109 insertions(+), 20 deletions(-) diff --git a/native/src/base/files.cpp b/native/src/base/files.cpp index c3f901dc4..884ccae4c 100644 --- a/native/src/base/files.cpp +++ b/native/src/base/files.cpp @@ -1,10 +1,12 @@ #include +#include #include #include #include #include #include +#include #include using namespace std; @@ -382,6 +384,86 @@ void parse_mnt(const char *file, const function &fn) { } } +std::vector parse_mount_info(const char *pid) { + char buf[PATH_MAX] = {}; + ssprintf(buf, sizeof(buf), "/proc/%s/mountinfo", pid); + std::vector result; + + file_readline(buf, [&result](string_view line) -> bool { + int root_start = 0, root_end = 0; + int target_start = 0, target_end = 0; + int vfs_option_start = 0, vfs_option_end = 0; + int type_start = 0, type_end = 0; + int source_start = 0, source_end = 0; + int fs_option_start = 0, fs_option_end = 0; + int optional_start = 0, optional_end = 0; + unsigned int id, parent, maj, min; + sscanf(line.data(), + "%u " // (1) id + "%u " // (2) parent + "%u:%u " // (3) maj:min + "%n%*s%n " // (4) mountroot + "%n%*s%n " // (5) target + "%n%*s%n" // (6) vfs options (fs-independent) + "%n%*[^-]%n - " // (7) optional fields + "%n%*s%n " // (8) FS type + "%n%*s%n " // (9) source + "%n%*s%n", // (10) fs options (fs specific) + &id, &parent, &maj, &min, &root_start, &root_end, &target_start, + &target_end, &vfs_option_start, &vfs_option_end, + &optional_start, &optional_end, &type_start, &type_end, + &source_start, &source_end, &fs_option_start, &fs_option_end); + + auto root = line.substr(root_start, root_end - root_start); + auto target = line.substr(target_start, target_end - target_start); + auto vfs_option = + line.substr(vfs_option_start, vfs_option_end - vfs_option_start); + ++optional_start; + --optional_end; + auto optional = line.substr( + optional_start, + optional_end - optional_start > 0 ? optional_end - optional_start : 0); + + auto type = line.substr(type_start, type_end - type_start); + auto source = line.substr(source_start, source_end - source_start); + auto fs_option = + line.substr(fs_option_start, fs_option_end - fs_option_start); + + unsigned int shared = 0; + unsigned int master = 0; + unsigned int propagate_from = 0; + if (auto pos = optional.find("shared:"); pos != std::string_view::npos) { + shared = parse_int(optional.substr(pos + 7)); + } + if (auto pos = optional.find("master:"); pos != std::string_view::npos) { + master = parse_int(optional.substr(pos + 7)); + } + if (auto pos = optional.find("propagate_from:"); + pos != std::string_view::npos) { + propagate_from = parse_int(optional.substr(pos + 15)); + } + + result.emplace_back(mount_info { + .id = id, + .parent = parent, + .device = static_cast(makedev(maj, min)), + .root {root}, + .target {target}, + .vfs_option {vfs_option}, + .optional { + .shared = shared, + .master = master, + .propagate_from = propagate_from, + }, + .type {type}, + .source {source}, + .fs_option {fs_option}, + }); + return true; + }); + return result; +} + sDIR make_dir(DIR *dp) { return sDIR(dp, [](DIR *dp){ return dp ? closedir(dp) : 1; }); } diff --git a/native/src/base/files.hpp b/native/src/base/files.hpp index 1a44100b9..0244d5889 100644 --- a/native/src/base/files.hpp +++ b/native/src/base/files.hpp @@ -39,6 +39,23 @@ protected: void swap(byte_data &o); }; +struct mount_info { + unsigned int id; + unsigned int parent; + dev_t device; + std::string root; + std::string target; + std::string vfs_option; + struct { + unsigned int shared; + unsigned int master; + unsigned int propagate_from; + } optional; + std::string type; + std::string source; + std::string fs_option; +}; + struct mmap_data : public byte_data { mmap_data() = default; mmap_data(const mmap_data&) = delete; @@ -88,6 +105,7 @@ void parse_prop_file(const char *file, const std::function &fn); void frm_rf(int dirfd); void clone_dir(int src, int dest); +std::vector parse_mount_info(const char *pid); void parse_mnt(const char *file, const std::function &fn); std::string find_apk_path(const char *pkg); diff --git a/native/src/zygisk/deny/revert.cpp b/native/src/zygisk/deny/revert.cpp index 59a75b0ed..bf3807322 100644 --- a/native/src/zygisk/deny/revert.cpp +++ b/native/src/zygisk/deny/revert.cpp @@ -12,30 +12,19 @@ static void lazy_unmount(const char* mountpoint) { LOGD("denylist: Unmounted (%s)\n", mountpoint); } -#define TMPFS_MNT(dir) (mentry->mnt_type == "tmpfs"sv && str_starts(mentry->mnt_dir, "/" #dir)) - void revert_unmount() { vector targets; // Unmount dummy skeletons and MAGISKTMP - targets.push_back(MAGISKTMP); - parse_mnt("/proc/self/mounts", [&](mntent *mentry) { - if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext)) - targets.emplace_back(mentry->mnt_dir); - return true; - }); + // since mirror nodes are always mounted under skeleton, we don't have to specifically unmount + for (auto &info: parse_mount_info("self")) { + if (info.target.starts_with(MAGISKTMP) || // things in magisktmp + info.root.starts_with("/adb/modules") || // module nodes + info.root.starts_with("/" INTLROOT)) { // skeleton + targets.push_back(info.target); + } + } - for (auto &s : reversed(targets)) - lazy_unmount(s.data()); - targets.clear(); - - // Unmount all Magisk created mounts - parse_mnt("/proc/self/mounts", [&](mntent *mentry) { - if (str_contains(mentry->mnt_fsname, BLOCKDIR)) - targets.emplace_back(mentry->mnt_dir); - return true; - }); - - for (auto &s : reversed(targets)) + for (auto &s : targets) lazy_unmount(s.data()); }