diff --git a/module/jni/include/map_parser.hpp b/module/jni/include/map_parser.hpp index 8858c97..f3365b1 100644 --- a/module/jni/include/map_parser.hpp +++ b/module/jni/include/map_parser.hpp @@ -4,25 +4,28 @@ #include #include -class map_entry_t +namespace Parsers { -public: - map_entry_t(uintptr_t address_start, uintptr_t address_end, uintptr_t offset, - const std::string &perms, const std::string &pathname, dev_t device, ino_t inode); + class map_entry_t + { + public: + map_entry_t(uintptr_t address_start, uintptr_t address_end, uintptr_t offset, + const std::string &perms, const std::string &pathname, dev_t device, ino_t inode); - uintptr_t getAddressStart() const; - uintptr_t getAddressEnd() const; - const std::string &getPerms() const; - uintptr_t getOffset() const; - dev_t getDevice() const; - ino_t getInode() const; - const std::string &getPathname() const; + uintptr_t getAddressStart() const; + uintptr_t getAddressEnd() const; + const std::string &getPerms() const; + uintptr_t getOffset() const; + dev_t getDevice() const; + ino_t getInode() const; + const std::string &getPathname() const; -private: - uintptr_t address_start, address_end, offset; - std::string perms, pathname; - dev_t device; - ino_t inode; -}; + private: + uintptr_t address_start, address_end, offset; + std::string perms, pathname; + dev_t device; + ino_t inode; + }; -const std::vector &parseSelfMaps(bool cached = true); + const std::vector &parseSelfMaps(bool cached = true); +} diff --git a/module/jni/include/mount_parser.hpp b/module/jni/include/mount_parser.hpp index 95150a1..b81b12e 100644 --- a/module/jni/include/mount_parser.hpp +++ b/module/jni/include/mount_parser.hpp @@ -2,25 +2,27 @@ #include #include #include - #include -class mount_entry_t +namespace Parsers { -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; + 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; -}; + 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); + 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 de5ccce..2a15f2e 100644 --- a/module/jni/include/mountinfo_parser.hpp +++ b/module/jni/include/mountinfo_parser.hpp @@ -3,31 +3,34 @@ #include #include -class mountinfo_entry_t +namespace Parsers { -public: - mountinfo_entry_t(int mount_id, int parent_id, int major, int minor, - 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); + class mountinfo_entry_t + { + public: + mountinfo_entry_t(int mount_id, int parent_id, int major, int minor, + 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); - int getMountId() const; - int getParentId() const; - int getMajor() const; - int getMinor() const; - const std::string &getRoot() const; - const std::string &getMountPoint() const; - const std::unordered_map &getMountOptions() const; - const std::string &getOptionalFields() const; - const std::string &getFilesystemType() const; - const std::string &getMountSource() const; - const std::unordered_map &getSuperOptions() const; + int getMountId() const; + int getParentId() const; + int getMajor() const; + int getMinor() const; + const std::string &getRoot() const; + const std::string &getMountPoint() const; + const std::unordered_map &getMountOptions() const; + const std::string &getOptionalFields() const; + const std::string &getFilesystemType() const; + const std::string &getMountSource() const; + const std::unordered_map &getSuperOptions() const; -private: - int mount_id, parent_id, major, minor; - std::string root, mount_point, optional_fields, filesystem_type, mount_source; - std::unordered_map mount_options, super_options; -}; + private: + int mount_id, parent_id, major, minor; + 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); + const std::vector &parseSelfMountinfo(bool cached = true); +} diff --git a/module/jni/include/utils.hpp b/module/jni/include/utils.hpp index 4237cb4..3fb3c3e 100644 --- a/module/jni/include/utils.hpp +++ b/module/jni/include/utils.hpp @@ -1,20 +1,31 @@ #pragma once #include #include +#include #include "logging.hpp" #include "zygisk.hpp" -#define DCL_HOOK_FUNC(ret, func, ...) \ - ret (*old_##func)(__VA_ARGS__) = nullptr; \ +#define DCL_HOOK_FUNC(ret, func, ...) \ + ret (*old_##func)(__VA_ARGS__) = nullptr; \ ret new_##func(__VA_ARGS__) -#define ASSERT_LOG(tag, expr) if(!(expr)) { \ - LOGE("%s:%d Assertion %s failed. %d:%s", tag, __LINE__, #expr, errno, std::strerror(errno)); } +#define ASSERT_LOG(tag, expr) \ + if (!(expr)) \ + { \ + LOGE("%s:%d Assertion %s failed. %d:%s", #tag, __LINE__, #expr, errno, std::strerror(errno)); \ + } -#define ASSERT_EXIT(tag, expr, ret) if(!(expr)) { \ - LOGE("%s:%d Assertion %s failed. %d:%s", tag, __LINE__, #expr, errno, std::strerror(errno)); \ - ret; } +#define ASSERT_DO(tag, expr, ret) \ + if (!(expr)) \ + { \ + LOGE("%s:%d Assertion %s failed. %d:%s", #tag, __LINE__, #expr, errno, std::strerror(errno)); \ + ret; \ + } -bool switchMountNS(int pid); -int isUserAppUID(int uid); -bool hookPLTByName(zygisk::Api *api, const std::string &libName, const std::string &symbolName, void *hookFunc, void **origFunc); +namespace Utils +{ + bool switchMountNS(int pid); + int isUserAppUID(int uid); + bool hookPLTByName(zygisk::Api *api, const std::string &libName, const std::string &symbolName, void *hookFunc, void **origFunc); + int executeLambdaInFork(const std::function &lambda); +} diff --git a/module/jni/main.cpp b/module/jni/main.cpp index 2f2d274..e8d0534 100644 --- a/module/jni/main.cpp +++ b/module/jni/main.cpp @@ -70,7 +70,7 @@ class ZygiskModule : public zygisk::ModuleBase bool isRoot = (flags & zygisk::StateFlag::PROCESS_GRANTED_ROOT) != 0; bool isOnDenylist = (flags & zygisk::StateFlag::PROCESS_ON_DENYLIST) != 0; bool isChildZygote = args->is_child_zygote != NULL && *args->is_child_zygote; - if (isRoot || !isOnDenylist || !isUserAppUID(args->uid)) + if (isRoot || !isOnDenylist || !Utils::isUserAppUID(args->uid)) { LOGD("Skipping ppid=%d uid=%d isChildZygote=%d", getppid(), args->uid, isChildZygote); return; @@ -80,20 +80,20 @@ class ZygiskModule : public zygisk::ModuleBase /* * Read the comment above unshare hook. */ - ASSERT_EXIT("preAppSpecialize", unshare(CLONE_NEWNS) != -1, return); + ASSERT_DO(preAppSpecialize, unshare(CLONE_NEWNS) != -1, return); /* * Mount the app mount namespace's root as MS_SLAVE, so every mount/umount from * Zygote shared pre-specialization namespace is propagated to this one. */ - ASSERT_EXIT("preAppSpecialize", mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) != -1, return); + ASSERT_DO(preAppSpecialize, mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) != -1, return); - ASSERT_EXIT("preAppSpecialize", hookPLTByName("libandroid_runtime.so", "unshare", new_unshare, &old_unshare), return); - ASSERT_EXIT("preAppSpecialize", hookPLTByName("libandroid_runtime.so", "setresuid", new_setresuid, &old_setresuid), return); + ASSERT_DO(preAppSpecialize, hookPLTByName("libandroid_runtime.so", "unshare", new_unshare, &old_unshare), return); + ASSERT_DO(preAppSpecialize, hookPLTByName("libandroid_runtime.so", "setresuid", new_setresuid, &old_setresuid), return); int companionFd = -1; - ASSERT_LOG("preAppSpecialize", (companionFd = api->connectCompanion()) != -1); - ASSERT_LOG("preAppSpecialize", companionFd != -1 && api->exemptFd(companionFd)); + ASSERT_LOG(preAppSpecialize, (companionFd = api->connectCompanion()) != -1); + ASSERT_LOG(preAppSpecialize, companionFd != -1 && api->exemptFd(companionFd)); callbackFunction = [fd = companionFd]() { @@ -103,8 +103,8 @@ class ZygiskModule : public zygisk::ModuleBase do { pid_t pid = getpid(); - ASSERT_EXIT("invokeZygiskCompanion", write(fd, &pid, sizeof(pid)) == sizeof(pid), break); - ASSERT_EXIT("invokeZygiskCompanion", read(fd, &result, sizeof(result)) == sizeof(result), break); + ASSERT_DO(invokeZygiskCompanion, write(fd, &pid, sizeof(pid)) == sizeof(pid), break); + ASSERT_DO(invokeZygiskCompanion, read(fd, &result, sizeof(result)) == sizeof(result), break); } while (false); close(fd); } @@ -133,15 +133,15 @@ class ZygiskModule : public zygisk::ModuleBase void postAppSpecialize(const AppSpecializeArgs *args) override { if (old_unshare != nullptr) - ASSERT_LOG("postAppSpecialize", hookPLTByName("libandroid_runtime.so", "unshare", old_unshare)); + ASSERT_LOG(postAppSpecialize, hookPLTByName("libandroid_runtime.so", "unshare", old_unshare)); if (old_setresuid != nullptr) - ASSERT_LOG("postAppSpecialize", hookPLTByName("libandroid_runtime.so", "setresuid", old_setresuid)); + ASSERT_LOG(postAppSpecialize, hookPLTByName("libandroid_runtime.so", "setresuid", old_setresuid)); } template bool hookPLTByName(const std::string &libName, const std::string &symbolName, T *hookFunction, T **originalFunction = nullptr) { - return ::hookPLTByName(api, libName, symbolName, (void *)hookFunction, (void **)originalFunction) && api->pltHookCommit(); + return Utils::hookPLTByName(api, libName, symbolName, (void *)hookFunction, (void **)originalFunction) && api->pltHookCommit(); } private: @@ -154,18 +154,21 @@ void zygisk_companion_handler(int fd) bool result = [&]() -> bool { pid_t pid; - ASSERT_EXIT("zygisk_companion_handler", read(fd, &pid, sizeof(pid)) == sizeof(pid), return false); - ASSERT_EXIT("zygisk_companion_handler", unshare(CLONE_NEWNS) != -1, return false); - ASSERT_EXIT("zygisk_companion_handler", switchMountNS(pid), return false); + ASSERT_DO(zygisk_companion_handler, read(fd, &pid, sizeof(pid)) == sizeof(pid), return false); + ASSERT_DO(zygisk_companion_handler, unshare(CLONE_NEWNS) != -1, return false); + ASSERT_DO(zygisk_companion_handler, Utils::switchMountNS(pid), return false); LOGD("zygisk_companion_handler processing namespace of pid=%d", pid); - doUnmount(); - doRemount(); - - return true; + // setns mount namespace is not effective until a fork(?) + return WIFEXITED(Utils::executeLambdaInFork( + []() + { + doUnmount(); + doRemount(); + })); }(); - ASSERT_LOG("zygisk_companion_handler", write(fd, &result, sizeof(result)) == sizeof(result)); + ASSERT_LOG(zygisk_companion_handler, write(fd, &result, sizeof(result)) == sizeof(result)); } REGISTER_ZYGISK_MODULE(ZygiskModule) diff --git a/module/jni/map_parser.cpp b/module/jni/map_parser.cpp index db30060..19b2cb5 100644 --- a/module/jni/map_parser.cpp +++ b/module/jni/map_parser.cpp @@ -7,6 +7,8 @@ #include "map_parser.hpp" #include "logging.hpp" +using namespace Parsers; + map_entry_t::map_entry_t(uintptr_t address_start, uintptr_t address_end, uintptr_t offset, const std::string &perms, const std::string &pathname, dev_t device, ino_t inode) : address_start(address_start), address_end(address_end), perms(perms), offset(offset), device(device), inode(inode), pathname(pathname) {} @@ -19,7 +21,7 @@ dev_t map_entry_t::getDevice() const { return device; } ino_t map_entry_t::getInode() const { return inode; } const std::string &map_entry_t::getPathname() const { return pathname; } -const std::vector &parseSelfMaps(bool cached) +const std::vector &Parsers::parseSelfMaps(bool cached) { static std::vector parser_cache; if (cached && !parser_cache.empty()) diff --git a/module/jni/modules.cpp b/module/jni/modules.cpp index 897fcef..bf944ee 100644 --- a/module/jni/modules.cpp +++ b/module/jni/modules.cpp @@ -23,7 +23,7 @@ static const std::unordered_map mount_flags_procfs = { {"relatime", MS_RELATIME}, {"nosymfollow", MS_NOSYMFOLLOW}}; -static bool shouldUnmount(const mountinfo_entry_t &mount_info) +static bool shouldUnmount(const Parsers::mountinfo_entry_t &mount_info) { const auto &root = mount_info.getRoot(); @@ -31,7 +31,7 @@ static bool shouldUnmount(const mountinfo_entry_t &mount_info) return root.starts_with("/adb/"); } -static bool shouldUnmount(const mount_entry_t &mount) +static bool shouldUnmount(const Parsers::mount_entry_t &mount) { const auto &mountPoint = mount.getMountPoint(); const auto &type = mount.getType(); @@ -66,7 +66,7 @@ void doUnmount() std::vector mountPoints; // Check mounts first - for (const auto &mount : parseSelfMounts(false)) + for (const auto &mount : Parsers::parseSelfMounts(false)) { if (shouldUnmount(mount)) { @@ -75,7 +75,7 @@ void doUnmount() } // Check mountinfos so that we can find bind mounts as well - for (const auto &mount_info : parseSelfMountinfo(false)) + for (const auto &mount_info : Parsers::parseSelfMountinfo(false)) { if (shouldUnmount(mount_info)) { @@ -102,7 +102,7 @@ void doUnmount() void doRemount() { - for (const auto &mount : parseSelfMounts(false)) + for (const auto &mount : Parsers::parseSelfMounts(false)) { if (mount.getMountPoint() == "/data") { @@ -146,7 +146,7 @@ void doHideZygisk() std::string filePath; uintptr_t startAddress = 0, bssAddress = 0; - for (const auto &map : parseSelfMaps()) + for (const auto &map : Parsers::parseSelfMaps()) { if (map.getPathname().ends_with("/libnativebridge.so") && map.getPerms() == "r--p") { @@ -157,8 +157,8 @@ void doHideZygisk() } } - ASSERT_EXIT("doHideZygisk", startAddress != 0, return); - ASSERT_EXIT("doHideZygisk", reader.load(filePath), return); + ASSERT_DO(doHideZygisk, startAddress != 0, return); + ASSERT_DO(doHideZygisk, reader.load(filePath), return); size_t bssSize = 0; for (const auto &sec : reader.sections) @@ -171,7 +171,7 @@ void doHideZygisk() } } - ASSERT_EXIT("doHideZygisk", bssAddress != 0, return); + ASSERT_DO(doHideZygisk, bssAddress != 0, return); LOGD("Found .bss for \"%s\" at 0x%" PRIxPTR " sized %" PRIuPTR " bytes.", filePath.c_str(), bssAddress, bssSize); uint8_t *pHadError = reinterpret_cast(memchr(reinterpret_cast(bssAddress), 0x01, bssSize)); diff --git a/module/jni/mount_parser.cpp b/module/jni/mount_parser.cpp index 689399a..a624a16 100644 --- a/module/jni/mount_parser.cpp +++ b/module/jni/mount_parser.cpp @@ -9,6 +9,8 @@ #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) { @@ -22,7 +24,7 @@ const std::unordered_map &mount_entry_t::getOptions() int mount_entry_t::getDumpFrequency() const { return freq; } int mount_entry_t::getPassNumber() const { return passno; } -const std::vector &parseSelfMounts(bool cached) +const std::vector &Parsers::parseSelfMounts(bool cached) { static std::vector parser_cache; if (cached && !parser_cache.empty()) @@ -32,7 +34,7 @@ const std::vector &parseSelfMounts(bool cached) parser_cache.clear(); FILE *file; - ASSERT_EXIT("parseSelfMounts", (file = setmntent("/proc/self/mounts", "r")) != NULL, return parser_cache); + ASSERT_DO(parseSelfMounts, (file = setmntent("/proc/self/mounts", "r")) != NULL, return parser_cache); struct mntent *entry; while ((entry = getmntent(file)) != NULL) @@ -44,7 +46,7 @@ const std::vector &parseSelfMounts(bool cached) return parser_cache; } -std::unordered_map parseMountOptions(const std::string &input) +std::unordered_map Parsers::parseMountOptions(const std::string &input) { std::unordered_map ret; std::istringstream iss(input); diff --git a/module/jni/mountinfo_parser.cpp b/module/jni/mountinfo_parser.cpp index ad71382..a1fbff1 100644 --- a/module/jni/mountinfo_parser.cpp +++ b/module/jni/mountinfo_parser.cpp @@ -8,6 +8,8 @@ #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, const std::string &root, const std::string &mount_point, const std::string &mount_options, const std::string &optional_fields, @@ -34,7 +36,7 @@ const std::string &mountinfo_entry_t::getFilesystemType() const { return filesys const std::string &mountinfo_entry_t::getMountSource() const { return mount_source; } const std::unordered_map &mountinfo_entry_t::getSuperOptions() const { return super_options; } -const std::vector &parseSelfMountinfo(bool cached) +const std::vector &Parsers::parseSelfMountinfo(bool cached) { static std::vector parser_cache; if (cached && !parser_cache.empty()) diff --git a/module/jni/utils.cpp b/module/jni/utils.cpp index 42d93c2..323e17b 100644 --- a/module/jni/utils.cpp +++ b/module/jni/utils.cpp @@ -1,6 +1,8 @@ #include +#include #include #include +#include #include #include @@ -10,9 +12,11 @@ #include "zygisk.hpp" #include "logging.hpp" -bool hookPLTByName(zygisk::Api *api, const std::string &libName, const std::string &symbolName, void *hookFunc, void **origFunc) +using namespace Utils; + +bool Utils::hookPLTByName(zygisk::Api *api, const std::string &libName, const std::string &symbolName, void *hookFunc, void **origFunc) { - for (const auto &map : parseSelfMaps()) + for (const auto &map : Parsers::parseSelfMaps()) { if (map.getPathname().ends_with("/" + libName)) { @@ -23,7 +27,7 @@ bool hookPLTByName(zygisk::Api *api, const std::string &libName, const std::stri return false; } -int isUserAppUID(int uid) +int Utils::isUserAppUID(int uid) { int appid = uid % AID_USER_OFFSET; if (appid >= AID_APP_START && appid <= AID_APP_END) @@ -33,7 +37,7 @@ int isUserAppUID(int uid) return false; } -bool switchMountNS(int pid) +bool Utils::switchMountNS(int pid) { std::string path = std::string("/proc/") + std::to_string(pid) + "/ns/mnt"; int ret, fd; @@ -46,3 +50,23 @@ bool switchMountNS(int pid) close(fd); return ret == 0; } + +int Utils::executeLambdaInFork(const std::function &lambda) +{ + pid_t pid = fork(); + ASSERT_DO(executeLambdaInFork, pid != -1, return -1); + + if (pid == 0) + { + // Child process + lambda(); + exit(EXIT_SUCCESS); + } + else + { + // Parent process + int status = -1; + waitpid(pid, &status, 0); + return status; + } +}