From 7cbb41bbb6a11092e05c8c2c7f34011ee2030e97 Mon Sep 17 00:00:00 2001 From: snake-4 <18491360+snake-4@users.noreply.github.com> Date: Sun, 28 Apr 2024 14:09:15 +0200 Subject: [PATCH] Added mountinfo_root_resolver and removed... mount_parser. --- module/jni/Android.mk | 2 +- module/jni/include/mount_parser.hpp | 28 --------- module/jni/include/mountinfo_parser.hpp | 19 ++++-- module/jni/modules.cpp | 80 +++++++++---------------- module/jni/mount_parser.cpp | 66 -------------------- module/jni/mountinfo_parser.cpp | 61 ++++++++++++++++--- 6 files changed, 98 insertions(+), 158 deletions(-) delete mode 100644 module/jni/include/mount_parser.hpp delete mode 100644 module/jni/mount_parser.cpp diff --git a/module/jni/Android.mk b/module/jni/Android.mk index 245b2eb..0d3c95f 100644 --- a/module/jni/Android.mk +++ b/module/jni/Android.mk @@ -3,7 +3,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/elfio LOCAL_MODULE := zygisk -LOCAL_SRC_FILES := utils.cpp map_parser.cpp mount_parser.cpp mountinfo_parser.cpp modules.cpp main.cpp +LOCAL_SRC_FILES := utils.cpp map_parser.cpp mountinfo_parser.cpp modules.cpp main.cpp LOCAL_STATIC_LIBRARIES := libcxx LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) diff --git a/module/jni/include/mount_parser.hpp b/module/jni/include/mount_parser.hpp deleted file mode 100644 index b81b12e..0000000 --- a/module/jni/include/mount_parser.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace Parsers -{ - class mount_entry_t - { - public: - mount_entry_t(::mntent *entry); - const std::string &getFsName() const; - const std::string &getMountPoint() const; - const std::string &getType() const; - const std::unordered_map &getOptions() const; - int getDumpFrequency() const; - int getPassNumber() const; - - private: - std::string fsname, dir, type; - std::unordered_map opts_map; - int freq, passno; - }; - - const std::vector &parseSelfMounts(bool cached = true); - std::unordered_map parseMountOptions(const std::string &input); -} diff --git a/module/jni/include/mountinfo_parser.hpp b/module/jni/include/mountinfo_parser.hpp index 2a15f2e..675aa1a 100644 --- a/module/jni/include/mountinfo_parser.hpp +++ b/module/jni/include/mountinfo_parser.hpp @@ -2,13 +2,14 @@ #include #include #include +#include namespace Parsers { class mountinfo_entry_t { public: - mountinfo_entry_t(int mount_id, int parent_id, int major, int minor, + mountinfo_entry_t(int mount_id, int parent_id, dev_t device, const std::string &root, const std::string &mount_point, const std::string &mount_options, const std::string &optional_fields, const std::string &filesystem_type, const std::string &mount_source, @@ -16,8 +17,7 @@ namespace Parsers int getMountId() const; int getParentId() const; - int getMajor() const; - int getMinor() const; + dev_t getDevice() const; const std::string &getRoot() const; const std::string &getMountPoint() const; const std::unordered_map &getMountOptions() const; @@ -27,10 +27,21 @@ namespace Parsers const std::unordered_map &getSuperOptions() const; private: - int mount_id, parent_id, major, minor; + dev_t device; + int mount_id, parent_id; std::string root, mount_point, optional_fields, filesystem_type, mount_source; std::unordered_map mount_options, super_options; }; const std::vector &parseSelfMountinfo(bool cached = true); + + class mountinfo_root_resolver + { + public: + mountinfo_root_resolver(const std::vector &mount_infos); + std::string resolveRootOf(const mountinfo_entry_t &mount_info) const; + + private: + std::unordered_map device_mount_map; + }; } diff --git a/module/jni/modules.cpp b/module/jni/modules.cpp index bf944ee..4c820f8 100644 --- a/module/jni/modules.cpp +++ b/module/jni/modules.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -9,10 +8,11 @@ #include "zygisk.hpp" #include "logging.hpp" #include "map_parser.hpp" -#include "mount_parser.hpp" #include "mountinfo_parser.hpp" #include "utils.hpp" +using namespace Parsers; + static const std::set fsname_list = {"KSU", "APatch", "magisk", "worker"}; static const std::unordered_map mount_flags_procfs = { {"nosuid", MS_NOSUID}, @@ -23,31 +23,29 @@ static const std::unordered_map mount_flags_procfs = { {"relatime", MS_RELATIME}, {"nosymfollow", MS_NOSYMFOLLOW}}; -static bool shouldUnmount(const Parsers::mountinfo_entry_t &mount_info) +static bool shouldUnmount(const mountinfo_entry_t &mount, const mountinfo_root_resolver &root_resolver) { - const auto &root = mount_info.getRoot(); - - // Unmount all module bind mounts - return root.starts_with("/adb/"); -} + const auto true_root = root_resolver.resolveRootOf(mount); + const auto &mount_point = mount.getMountPoint(); + const auto &type = mount.getFilesystemType(); -static bool shouldUnmount(const Parsers::mount_entry_t &mount) -{ - const auto &mountPoint = mount.getMountPoint(); - const auto &type = mount.getType(); - const auto &options = mount.getOptions(); + // Mount is from /data/adb + if (true_root.starts_with("/data/adb")) + return true; - // Unmount everything mounted to /data/adb - if (mountPoint.starts_with("/data/adb")) + // Mount is to /data/adb + if (mount_point.starts_with("/data/adb")) return true; // Unmount all module overlayfs and tmpfs - if ((type == "overlay" || type == "tmpfs") && fsname_list.contains(mount.getFsName())) + if ((type == "overlay" || type == "tmpfs") && fsname_list.contains(mount.getMountSource())) return true; // Unmount all overlayfs with lowerdir/upperdir/workdir starting with /data/adb if (type == "overlay") { + const auto &options = mount.getSuperOptions(); + if (options.contains("lowerdir") && options.at("lowerdir").starts_with("/data/adb")) return true; @@ -63,58 +61,38 @@ static bool shouldUnmount(const Parsers::mount_entry_t &mount) void doUnmount() { - std::vector mountPoints; - - // Check mounts first - for (const auto &mount : Parsers::parseSelfMounts(false)) - { - if (shouldUnmount(mount)) - { - mountPoints.push_back(mount.getMountPoint()); - } - } + const auto &mount_infos = parseSelfMountinfo(false); + auto root_resolver = mountinfo_root_resolver(mount_infos); - // Check mountinfos so that we can find bind mounts as well - for (const auto &mount_info : Parsers::parseSelfMountinfo(false)) + for (auto it = mount_infos.rbegin(); it != mount_infos.rend(); it++) { - if (shouldUnmount(mount_info)) - { - mountPoints.push_back(mount_info.getMountPoint()); - } - } - - // Sort by string lengths, descending - std::sort(mountPoints.begin(), mountPoints.end(), [](const auto &lhs, const auto &rhs) - { return lhs.size() > rhs.size(); }); - - for (const auto &mountPoint : mountPoints) - { - if (umount2(mountPoint.c_str(), MNT_DETACH) == 0) - { - LOGD("umount2(\"%s\", MNT_DETACH) returned 0", mountPoint.c_str()); - } - else + if (shouldUnmount(*it, root_resolver)) { - LOGW("umount2(\"%s\", MNT_DETACH) returned -1: %d (%s)", mountPoint.c_str(), errno, strerror(errno)); + const auto &mount_point_cstr = it->getMountPoint().c_str(); + if (umount2(mount_point_cstr, MNT_DETACH) == 0) + LOGD("umount2(\"%s\", MNT_DETACH) returned 0", mount_point_cstr); + else + LOGW("umount2(\"%s\", MNT_DETACH) returned -1: %d (%s)", mount_point_cstr, errno, strerror(errno)); } } } void doRemount() { - for (const auto &mount : Parsers::parseSelfMounts(false)) + for (const auto &mount : parseSelfMountinfo(false)) { if (mount.getMountPoint() == "/data") { - const auto &options = mount.getOptions(); + const auto &superOptions = mount.getSuperOptions(); + const auto &mountOptions = mount.getMountOptions(); // If errors=remount-ro, remount it with errors=continue - if (options.contains("errors") && options.at("errors") == "remount-ro") + if (superOptions.contains("errors") && superOptions.at("errors") == "remount-ro") { unsigned long flags = MS_REMOUNT; for (const auto &flagName : mount_flags_procfs) { - if (options.contains(flagName.first)) + if (mountOptions.contains(flagName.first)) flags |= flagName.second; } @@ -146,7 +124,7 @@ void doHideZygisk() std::string filePath; uintptr_t startAddress = 0, bssAddress = 0; - for (const auto &map : Parsers::parseSelfMaps()) + for (const auto &map : parseSelfMaps()) { if (map.getPathname().ends_with("/libnativebridge.so") && map.getPerms() == "r--p") { diff --git a/module/jni/mount_parser.cpp b/module/jni/mount_parser.cpp deleted file mode 100644 index a624a16..0000000 --- a/module/jni/mount_parser.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "mount_parser.hpp" -#include "logging.hpp" -#include "utils.hpp" - -using namespace Parsers; - -mount_entry_t::mount_entry_t(::mntent *entry) - : fsname(entry->mnt_fsname), dir(entry->mnt_dir), type(entry->mnt_type), freq(entry->mnt_freq), passno(entry->mnt_passno) -{ - opts_map = parseMountOptions(entry->mnt_opts); -} - -const std::string &mount_entry_t::getFsName() const { return fsname; } -const std::string &mount_entry_t::getMountPoint() const { return dir; } -const std::string &mount_entry_t::getType() const { return type; } -const std::unordered_map &mount_entry_t::getOptions() const { return opts_map; } -int mount_entry_t::getDumpFrequency() const { return freq; } -int mount_entry_t::getPassNumber() const { return passno; } - -const std::vector &Parsers::parseSelfMounts(bool cached) -{ - static std::vector parser_cache; - if (cached && !parser_cache.empty()) - { - return parser_cache; - } - parser_cache.clear(); - - FILE *file; - ASSERT_DO(parseSelfMounts, (file = setmntent("/proc/self/mounts", "r")) != NULL, return parser_cache); - - struct mntent *entry; - while ((entry = getmntent(file)) != NULL) - { - parser_cache.emplace_back(mount_entry_t(entry)); - } - - endmntent(file); - return parser_cache; -} - -std::unordered_map Parsers::parseMountOptions(const std::string &input) -{ - std::unordered_map ret; - std::istringstream iss(input); - std::string token; - while (std::getline(iss, token, ',')) - { - std::istringstream tokenStream(token); - std::string key, value; - - if (std::getline(tokenStream, key, '=')) - { - std::getline(tokenStream, value); // Put what's left in the stream to value, could be empty - ret[key] = value; - } - } - return ret; -} diff --git a/module/jni/mountinfo_parser.cpp b/module/jni/mountinfo_parser.cpp index a1fbff1..7407d1a 100644 --- a/module/jni/mountinfo_parser.cpp +++ b/module/jni/mountinfo_parser.cpp @@ -3,19 +3,39 @@ #include #include #include +#include +#include #include "mountinfo_parser.hpp" -#include "mount_parser.hpp" #include "logging.hpp" using namespace Parsers; -mountinfo_entry_t::mountinfo_entry_t(int mount_id, int parent_id, int major, int minor, +static std::unordered_map parseMountOptions(const std::string &input) +{ + std::unordered_map ret; + std::istringstream iss(input); + std::string token; + while (std::getline(iss, token, ',')) + { + std::istringstream tokenStream(token); + std::string key, value; + + if (std::getline(tokenStream, key, '=')) + { + std::getline(tokenStream, value); // Put what's left in the stream to value, could be empty + ret[key] = value; + } + } + return ret; +} + +mountinfo_entry_t::mountinfo_entry_t(int mount_id, int parent_id, dev_t device, const std::string &root, const std::string &mount_point, const std::string &mount_options, const std::string &optional_fields, const std::string &filesystem_type, const std::string &mount_source, const std::string &super_options) - : mount_id(mount_id), parent_id(parent_id), major(major), minor(minor), + : mount_id(mount_id), parent_id(parent_id), device(device), root(root), mount_point(mount_point), optional_fields(optional_fields), filesystem_type(filesystem_type), mount_source(mount_source) @@ -26,8 +46,7 @@ mountinfo_entry_t::mountinfo_entry_t(int mount_id, int parent_id, int major, int int mountinfo_entry_t::getMountId() const { return mount_id; } int mountinfo_entry_t::getParentId() const { return parent_id; } -int mountinfo_entry_t::getMajor() const { return major; } -int mountinfo_entry_t::getMinor() const { return minor; } +dev_t mountinfo_entry_t::getDevice() const { return device; } const std::string &mountinfo_entry_t::getRoot() const { return root; } const std::string &mountinfo_entry_t::getMountPoint() const { return mount_point; } const std::unordered_map &mountinfo_entry_t::getMountOptions() const { return mount_options; } @@ -56,12 +75,12 @@ const std::vector &Parsers::parseSelfMountinfo(bool cached) { std::istringstream iss(line); - int mount_id, parent_id, major, minor; + int mount_id, parent_id, _major, _minor; std::string root, mount_point, mount_options, optional_fields, filesystem_type, mount_source, super_options; char colon; // Read the first 6 fields (major, colon and minor are the same field) - iss >> mount_id >> parent_id >> major >> colon >> minor >> root >> mount_point >> mount_options; + iss >> mount_id >> parent_id >> _major >> colon >> _minor >> root >> mount_point >> mount_options; if (iss.fail()) { LOGE("parseSelfMountinfo failed to parse the first 6 fields of line: %s", line.c_str()); @@ -87,7 +106,7 @@ const std::vector &Parsers::parseSelfMountinfo(bool cached) continue; } - parser_cache.emplace_back(mountinfo_entry_t(mount_id, parent_id, major, minor, + parser_cache.emplace_back(mountinfo_entry_t(mount_id, parent_id, makedev(_major, _minor), root, mount_point, mount_options, optional_fields, filesystem_type, mount_source, super_options)); @@ -95,3 +114,29 @@ const std::vector &Parsers::parseSelfMountinfo(bool cached) return parser_cache; } + +mountinfo_root_resolver::mountinfo_root_resolver(const std::vector &mount_infos) +{ + for (const auto &mount_info : mount_infos) + { + if (mount_info.getRoot() == "/") + { + device_mount_map[mount_info.getDevice()] = mount_info.getMountPoint(); + } + } +} + +std::string mountinfo_root_resolver::resolveRootOf(const mountinfo_entry_t &mount_info) const +{ + auto dev = mount_info.getDevice(); + if (device_mount_map.contains(dev)) + { + const auto &mount_root = device_mount_map.at(dev); + + // If mount root is /, mount_info root will already be the true root + if (mount_root != "/") + return mount_root + mount_info.getRoot(); + } + + return mount_info.getRoot(); +}