From f200aa4561a6cc855eed129e0b86405a82648d59 Mon Sep 17 00:00:00 2001 From: snake-4 <18491360+snake-4@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:49:25 +0200 Subject: [PATCH] Added root companion and logging macros --- module/jni/include/logging.hpp | 4 +- module/jni/include/utils.hpp | 10 +++++ module/jni/main.cpp | 80 +++++++++++++++++++++++++--------- module/jni/mount_parser.cpp | 9 ++-- module/jni/unmount.cpp | 13 ++---- module/jni/utils.cpp | 19 ++++++++ 6 files changed, 97 insertions(+), 38 deletions(-) diff --git a/module/jni/include/logging.hpp b/module/jni/include/logging.hpp index 9f6cd0f..5d96271 100644 --- a/module/jni/include/logging.hpp +++ b/module/jni/include/logging.hpp @@ -6,10 +6,10 @@ #ifndef NDEBUG static constexpr auto TAG = "ZygiskAssistant/JNI"; #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) #else #define LOGD(...) -#define LOGI(...) +#define LOGW(...) #define LOGE(...) #endif diff --git a/module/jni/include/utils.hpp b/module/jni/include/utils.hpp index dc725eb..4237cb4 100644 --- a/module/jni/include/utils.hpp +++ b/module/jni/include/utils.hpp @@ -1,10 +1,20 @@ #pragma once #include +#include +#include "logging.hpp" #include "zygisk.hpp" #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_EXIT(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); diff --git a/module/jni/main.cpp b/module/jni/main.cpp index c0f31d1..ccc597a 100644 --- a/module/jni/main.cpp +++ b/module/jni/main.cpp @@ -1,6 +1,10 @@ #include #include #include +#include + +#include +#include #include "zygisk.hpp" #include "logging.hpp" @@ -13,6 +17,8 @@ using zygisk::ServerSpecializeArgs; void doUnmount(); void doRemount(); +static std::function callbackFunction = []() {}; + /* * [What's the purpose of this hook?] * Calling unshare twice invalidates existing FD links, which fails Zygote sanity checks. @@ -28,9 +34,7 @@ void doRemount(); */ DCL_HOOK_FUNC(static int, unshare, int flags) { - doUnmount(); - doRemount(); - + callbackFunction(); // Do not allow CLONE_NEWNS. flags &= ~(CLONE_NEWNS); if (!flags) @@ -68,27 +72,41 @@ public: /* * Read the comment above unshare hook. */ - if (unshare(CLONE_NEWNS) == -1) - { - LOGE("unshare(CLONE_NEWNS) returned -1: %d (%s)", errno, strerror(errno)); - return; - } + ASSERT_EXIT("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. */ - if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) - { - LOGE("mount(\"rootfs\", \"/\", NULL, (MS_SLAVE | MS_REC), NULL) returned -1: %d (%s)", errno, strerror(errno)); - return; - } + ASSERT_EXIT("preAppSpecialize", mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) != -1, return); - if (!hookPLTByName("libandroid_runtime.so", "unshare", new_unshare, &old_unshare)) + ASSERT_EXIT("preAppSpecialize", hookPLTByName("libandroid_runtime.so", "unshare", new_unshare, &old_unshare), return); + + ASSERT_LOG("preAppSpecialize", (companionFd = api->connectCompanion()) != -1); + + callbackFunction = [fd = companionFd]() { - LOGE("plt_hook_wrapper(\"libandroid_runtime.so\", \"unshare\", new_unshare, old_unshare) returned false"); - return; - } + bool result = false; + if (fd != -1) + { + 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); + } while (false); + close(fd); + } + + if (result) + LOGD("Invoking the companion was successful."); + else + { + LOGW("Invoking the companion failed. Performing operations in Zygote context!"); + doUnmount(); + doRemount(); + } + }; } void preServerSpecialize(ServerSpecializeArgs *args) override @@ -98,10 +116,8 @@ public: void postAppSpecialize(const AppSpecializeArgs *args) override { - if (old_unshare != nullptr && !hookPLTByName("libandroid_runtime.so", "unshare", old_unshare)) - { - LOGE("plt_hook_wrapper(\"libandroid_runtime.so\", \"unshare\", old_unshare) returned false"); - } + if (old_unshare != nullptr) + ASSERT_LOG("postAppSpecialize", hookPLTByName("libandroid_runtime.so", "unshare", old_unshare)); } template @@ -111,8 +127,30 @@ public: } private: + int companionFd = -1; Api *api; JNIEnv *env; }; +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); + LOGD("zygisk_companion_handler received pid=%d", pid); + + ASSERT_EXIT("zygisk_companion_handler", unshare(CLONE_NEWNS) != -1, return false); + ASSERT_EXIT("zygisk_companion_handler", switchMountNS(pid), return false); + + doUnmount(); + doRemount(); + + return true; + }(); + + ASSERT_LOG("zygisk_companion_handler", write(fd, &result, sizeof(result)) == sizeof(result)); +} + REGISTER_ZYGISK_MODULE(ZygiskModule) +REGISTER_ZYGISK_COMPANION(zygisk_companion_handler) diff --git a/module/jni/mount_parser.cpp b/module/jni/mount_parser.cpp index 8392ac9..651f06a 100644 --- a/module/jni/mount_parser.cpp +++ b/module/jni/mount_parser.cpp @@ -7,6 +7,7 @@ #include "mount_parser.hpp" #include "logging.hpp" +#include "utils.hpp" 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) @@ -25,12 +26,8 @@ std::vector parseMountsFromPath(const char *path) { std::vector result; - FILE *file = setmntent(path, "r"); - if (file == NULL) - { - LOGE("setmntent(\"%s\", \"r\") returned NULL: %d (%s)", path, errno, strerror(errno)); - return result; - } + FILE *file; + ASSERT_EXIT("parseMountsFromPath", (file = setmntent(path, "r")) != NULL, return result); struct mntent *entry; while ((entry = getmntent(file)) != NULL) diff --git a/module/jni/unmount.cpp b/module/jni/unmount.cpp index ad98fdb..908d825 100644 --- a/module/jni/unmount.cpp +++ b/module/jni/unmount.cpp @@ -8,6 +8,7 @@ #include "logging.hpp" #include "mount_parser.hpp" #include "mountinfo_parser.hpp" +#include "utils.hpp" constexpr std::array fsname_list = {"KSU", "APatch", "magisk", "worker"}; @@ -91,7 +92,7 @@ void doUnmount() } else { - LOGE("umount2(\"%s\", MNT_DETACH) returned -1: %d (%s)", mountPoint.c_str(), errno, strerror(errno)); + LOGW("umount2(\"%s\", MNT_DETACH) returned -1: %d (%s)", mountPoint.c_str(), errno, strerror(errno)); } } } @@ -108,14 +109,8 @@ void doRemount() // If errors=remount-ro, remount it with errors=continue if (options.find("errors") != options.end() && options.at("errors") == "remount-ro") { - if (mount(NULL, "/data", NULL, MS_REMOUNT, "errors=continue") == 0) - { - LOGD("mount(NULL, \"/data\", NULL, MS_REMOUNT, \"errors=continue\") returned 0"); - } - else - { - LOGE("mount(NULL, \"/data\", NULL, MS_REMOUNT, \"errors=continue\") returned -1: %d (%s)", errno, strerror(errno)); - } + LOGD("Trying to remount: /data"); + ASSERT_LOG("doRemount", mount(NULL, "/data", NULL, MS_REMOUNT, "errors=continue") == 0); } } } diff --git a/module/jni/utils.cpp b/module/jni/utils.cpp index ff7940c..8ce6e5f 100644 --- a/module/jni/utils.cpp +++ b/module/jni/utils.cpp @@ -1,9 +1,14 @@ #include +#include +#include +#include +#include #include "map_parser.hpp" #include "utils.hpp" #include "android_filesystem_config.h" #include "zygisk.hpp" +#include "logging.hpp" bool hookPLTByName(zygisk::Api *api, const std::string &libName, const std::string &symbolName, void *hookFunc, void **origFunc) { @@ -27,3 +32,17 @@ int isUserAppUID(int uid) return true; return false; } + +bool switchMountNS(int pid) +{ + std::string path = std::string("/proc/") + std::to_string(pid) + "/ns/mnt"; + int ret, fd; + if ((fd = open(path.c_str(), O_RDONLY)) < 0) + { + return false; + } + + ret = setns(fd, 0); + close(fd); + return ret == 0; +}