From a2af28dc6f66c0471d3319f5f5677c26dabf3e35 Mon Sep 17 00:00:00 2001 From: 5ec1cff <56485584+5ec1cff@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:27:21 +0800 Subject: [PATCH] add 32 bit support back & fix x86-64 support & fix jni hook restore (#59) * Add back 32 bit support & some fix * fix system server crash on android 10 * Refine code --------- Co-authored-by: Nullptr --- .github/workflows/ci.yml | 2 + loader/build.gradle.kts | 1 - loader/src/include/daemon.h | 8 +- loader/src/include/logging.h | 14 +- loader/src/injector/hook.cpp | 25 ++- loader/src/injector/jni_hooks.hpp | 60 ++----- module/build.gradle.kts | 4 +- module/src/customize.sh | 42 ++++- zygiskd/Cargo.toml | 3 +- zygiskd/build.gradle.kts | 6 +- zygiskd/src/constants.rs | 15 +- zygiskd/src/fuse.rs | 264 ++++++++---------------------- zygiskd/src/main.rs | 10 +- zygiskd/src/ptrace.rs | 233 ++++++++++++++++++++++++++ zygiskd/src/root_impl/kernelsu.rs | 2 +- zygiskd/src/utils.rs | 11 ++ zygiskd/src/watchdog.rs | 31 ++-- zygiskd/src/zygiskd.rs | 19 ++- 18 files changed, 444 insertions(+), 306 deletions(-) create mode 100644 zygiskd/src/ptrace.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6077db..09c743e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,8 @@ jobs: rustup override set nightly rustup target add aarch64-linux-android rustup target add x86_64-linux-android + rustup target add i686-linux-android + rustup target add armv7-linux-androideabi - name: Set up ccache uses: hendrikmuhs/ccache-action@v1.2 diff --git a/loader/build.gradle.kts b/loader/build.gradle.kts index b29a709..7e0b365 100644 --- a/loader/build.gradle.kts +++ b/loader/build.gradle.kts @@ -35,7 +35,6 @@ android { defaultConfig { externalNativeBuild { ndkBuild { - abiFilters("arm64-v8a", "x86_64") ccachePatch?.let { arguments += "NDK_CCACHE=$it" } diff --git a/loader/src/include/daemon.h b/loader/src/include/daemon.h index f15e9f5..2a177f3 100644 --- a/loader/src/include/daemon.h +++ b/loader/src/include/daemon.h @@ -5,7 +5,13 @@ #include #include -constexpr auto kCPSocketPath = "/dev/zygisk/cp.sock"; +#if defined(__LP64__) +# define LP_SELECT(lp32, lp64) lp64 +#else +# define LP_SELECT(lp32, lp64) lp32 +#endif + +constexpr auto kCPSocketPath = "/dev/zygisk/" LP_SELECT("cp32", "cp64") ".sock"; class UniqueFd { using Fd = int; diff --git a/loader/src/include/logging.h b/loader/src/include/logging.h index 6089a43..0318bbe 100644 --- a/loader/src/include/logging.h +++ b/loader/src/include/logging.h @@ -5,16 +5,13 @@ #include #ifndef LOG_TAG -#define LOG_TAG "zygisk-core" +#if defined(__LP64__) +# define LOG_TAG "zygisk-core64" +#else +# define LOG_TAG "zygisk-core32" +#endif #endif -#ifdef LOG_DISABLED -#define LOGD(...) -#define LOGV(...) -#define LOGI(...) -#define LOGW(...) -#define LOGE(...) -#else #ifndef NDEBUG #define LOGD(...) logging::log(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGV(...) logging::log(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) @@ -27,7 +24,6 @@ #define LOGE(...) logging::log(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define LOGF(...) logging::log(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__) #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)) -#endif namespace logging { void setfd(int fd); diff --git a/loader/src/injector/hook.cpp b/loader/src/injector/hook.cpp index c1b8471..382dbf9 100644 --- a/loader/src/injector/hook.cpp +++ b/loader/src/injector/hook.cpp @@ -26,6 +26,7 @@ using xstring = jni_hook::string; static void hook_unloader(); static void unhook_functions(); +static void restore_jni_env(JNIEnv *env); namespace { @@ -84,8 +85,16 @@ struct HookContext { vector register_info; vector ignore_info; - HookContext() : env(nullptr), args{nullptr}, process(nullptr), pid(-1), info_flags(0), - hook_info_lock(PTHREAD_MUTEX_INITIALIZER) { g_ctx = this; } + HookContext(JNIEnv *env, void *args) : + env(env), args{args}, process(nullptr), pid(-1), info_flags(0), + hook_info_lock(PTHREAD_MUTEX_INITIALIZER) { + static bool restored_env = false; + if (!restored_env) { + restore_jni_env(env); + restored_env = true; + } + g_ctx = this; + } ~HookContext(); /* Zygisksu changed: Load module fds */ @@ -685,12 +694,6 @@ HookContext::~HookContext() { should_unmap_zygisk = true; - // Restore JNIEnv - if (env->functions == new_functions) { - env->functions = old_functions; - delete new_functions; - } - // Unhook JNI methods for (const auto &[clz, methods] : *jni_hook_list) { if (!methods.empty() && env->RegisterNatives( @@ -713,6 +716,12 @@ HookContext::~HookContext() { } // namespace +static void restore_jni_env(JNIEnv *env) { + env->functions = old_functions; + delete new_functions; + new_functions = nullptr; +} + static bool hook_commit() { if (lsplt::CommitHook()) { return true; diff --git a/loader/src/injector/jni_hooks.hpp b/loader/src/injector/jni_hooks.hpp index 4445ad6..6ec6a95 100644 --- a/loader/src/injector/jni_hooks.hpp +++ b/loader/src/injector/jni_hooks.hpp @@ -5,9 +5,7 @@ namespace { void *nativeForkAndSpecialize_orig = nullptr; [[clang::no_stack_protector]] jint nativeForkAndSpecialize_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, instruction_set, app_data_dir @@ -18,9 +16,7 @@ void *nativeForkAndSpecialize_orig = nullptr; [[clang::no_stack_protector]] jint nativeForkAndSpecialize_o(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.fds_to_ignore = &fds_to_ignore; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir @@ -32,9 +28,7 @@ void *nativeForkAndSpecialize_orig = nullptr; AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.fds_to_ignore = &fds_to_ignore; args.is_child_zygote = &is_child_zygote; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir @@ -47,9 +41,7 @@ void *nativeForkAndSpecialize_orig = nullptr; args.fds_to_ignore = &fds_to_ignore; args.is_child_zygote = &is_child_zygote; args.is_top_app = &is_top_app; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app @@ -66,9 +58,7 @@ void *nativeForkAndSpecialize_orig = nullptr; args.whitelisted_data_info_list = &whitelisted_data_info_list; args.mount_data_dirs = &mount_data_dirs; args.mount_storage_dirs = &mount_storage_dirs; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs @@ -78,9 +68,7 @@ void *nativeForkAndSpecialize_orig = nullptr; } [[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_m(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _0, jint _1, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _0, _1, nice_name, fds_to_close, instruction_set, app_data_dir @@ -90,9 +78,7 @@ void *nativeForkAndSpecialize_orig = nullptr; } [[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_n(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _2, jint _3, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir, jint _4) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _2, _3, nice_name, fds_to_close, instruction_set, app_data_dir, _4 @@ -103,9 +89,7 @@ void *nativeForkAndSpecialize_orig = nullptr; [[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_o(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _5, jint _6, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.fds_to_ignore = &fds_to_ignore; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _5, _6, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir @@ -117,9 +101,7 @@ void *nativeForkAndSpecialize_orig = nullptr; AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.fds_to_ignore = &fds_to_ignore; args.is_child_zygote = &is_child_zygote; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkAndSpecialize_pre(); reinterpret_cast(nativeForkAndSpecialize_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _7, _8, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir @@ -180,9 +162,7 @@ void *nativeSpecializeAppProcess_orig = nullptr; [[clang::no_stack_protector]] void nativeSpecializeAppProcess_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.is_child_zygote = &is_child_zygote; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir @@ -193,9 +173,7 @@ void *nativeSpecializeAppProcess_orig = nullptr; AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.is_child_zygote = &is_child_zygote; args.is_top_app = &is_top_app; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app @@ -210,9 +188,7 @@ void *nativeSpecializeAppProcess_orig = nullptr; args.whitelisted_data_info_list = &whitelisted_data_info_list; args.mount_data_dirs = &mount_data_dirs; args.mount_storage_dirs = &mount_storage_dirs; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs @@ -222,9 +198,7 @@ void *nativeSpecializeAppProcess_orig = nullptr; [[clang::no_stack_protector]] void nativeSpecializeAppProcess_samsung_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _9, jint _10, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) { AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir); args.is_child_zygote = &is_child_zygote; - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeSpecializeAppProcess_pre(); reinterpret_cast(nativeSpecializeAppProcess_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _9, _10, nice_name, is_child_zygote, instruction_set, app_data_dir @@ -258,9 +232,7 @@ constexpr int nativeSpecializeAppProcess_methods_num = std::size(nativeSpecializ void *nativeForkSystemServer_orig = nullptr; [[clang::no_stack_protector]] jint nativeForkSystemServer_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) { ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities); - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkSystemServer_pre(); reinterpret_cast(nativeForkSystemServer_orig)( env, clazz, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities @@ -270,9 +242,7 @@ void *nativeForkSystemServer_orig = nullptr; } [[clang::no_stack_protector]] jint nativeForkSystemServer_samsung_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jint _11, jint _12, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) { ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities); - HookContext ctx; - ctx.env = env; - ctx.args = { &args }; + HookContext ctx(env, &args); ctx.nativeForkSystemServer_pre(); reinterpret_cast(nativeForkSystemServer_orig)( env, clazz, uid, gid, gids, runtime_flags, _11, _12, rlimits, permitted_capabilities, effective_capabilities diff --git a/module/build.gradle.kts b/module/build.gradle.kts index 52b9c19..48b81f0 100644 --- a/module/build.gradle.kts +++ b/module/build.gradle.kts @@ -39,7 +39,7 @@ androidComponents.onVariants { variant -> into(moduleDir) from("${rootProject.projectDir}/README.md") from("$projectDir/src") { - exclude("module.prop", "customize.sh", "service.sh") + exclude("module.prop", "customize.sh", "post-fs-data.sh", "service.sh") filter("eol" to FixCrLfFilter.CrLf.newInstance("lf")) } from("$projectDir/src") { @@ -52,7 +52,7 @@ androidComponents.onVariants { variant -> ) } from("$projectDir/src") { - include("customize.sh", "service.sh") + include("customize.sh", "post-fs-data.sh", "service.sh") val tokens = mapOf( "DEBUG" to if (buildTypeLowered == "debug") "true" else "false", "MIN_KSU_VERSION" to "$minKsuVersion", diff --git a/module/src/customize.sh b/module/src/customize.sh index 85de200..1575ac6 100644 --- a/module/src/customize.sh +++ b/module/src/customize.sh @@ -61,7 +61,7 @@ else fi # check architecture -if [ "$ARCH" != "arm64" ] && [ "$ARCH" != "x64" ]; then +if [ "$ARCH" != "arm" ] && [ "$ARCH" != "arm64" ] && [ "$ARCH" != "x86" ] && [ "$ARCH" != "x64" ]; then abort "! Unsupported platform: $ARCH" else ui_print "- Device platform: $ARCH" @@ -101,28 +101,54 @@ extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH" extract "$ZIPFILE" 'service.sh' "$MODPATH" mv "$TMPDIR/sepolicy.rule" "$MODPATH" +HAS32BIT=false && [ -d "/system/lib" ] && HAS32BIT=true + mkdir "$MODPATH/bin" mkdir "$MODPATH/system" mkdir "$MODPATH/system/lib64" +[ "$HAS32BIT" = true ] && mkdir "$MODPATH/system/lib" + +if [ "$ARCH" = "x86" ] || [ "$ARCH" = "x64" ]; then + if [ "$HAS32BIT" = true ]; then + ui_print "- Extracting x86 libraries" + extract "$ZIPFILE" 'bin/x86/zygiskd' "$MODPATH/bin" true + mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32" + extract "$ZIPFILE" 'lib/x86/libzygisk.so' "$MODPATH/system/lib" true + ln -sf "zygiskd32" "$MODPATH/bin/zygisk-cp32" + ln -sf "zygiskd32" "$MODPATH/bin/zygisk-ptrace32" + fi -if [ "$ARCH" = "x64" ]; then ui_print "- Extracting x64 libraries" extract "$ZIPFILE" 'bin/x86_64/zygiskd' "$MODPATH/bin" true + mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64" extract "$ZIPFILE" 'lib/x86_64/libzygisk.so' "$MODPATH/system/lib64" true - ln -sf "zygiskd" "$MODPATH/bin/zygisk-wd" - ln -sf "zygiskd" "$MODPATH/bin/zygisk-fuse" - ln -sf "zygiskd" "$MODPATH/bin/zygisk-cp" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-wd" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-fuse" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-cp64" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-ptrace64" else + if [ "$HAS32BIT" = true ]; then + ui_print "- Extracting arm libraries" + extract "$ZIPFILE" 'bin/armeabi-v7a/zygiskd' "$MODPATH/bin" true + mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32" + extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk.so' "$MODPATH/system/lib" true + ln -sf "zygiskd32" "$MODPATH/bin/zygisk-cp32" + ln -sf "zygiskd32" "$MODPATH/bin/zygisk-ptrace32" + fi + ui_print "- Extracting arm64 libraries" extract "$ZIPFILE" 'bin/arm64-v8a/zygiskd' "$MODPATH/bin" true + mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64" extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk.so' "$MODPATH/system/lib64" true - ln -sf "zygiskd" "$MODPATH/bin/zygisk-wd" - ln -sf "zygiskd" "$MODPATH/bin/zygisk-fuse" - ln -sf "zygiskd" "$MODPATH/bin/zygisk-cp" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-wd" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-fuse" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-cp64" + ln -sf "zygiskd64" "$MODPATH/bin/zygisk-ptrace64" fi ui_print "- Setting permissions" set_perm_recursive "$MODPATH/bin" 0 0 0755 0755 +set_perm_recursive "$MODPATH/system/lib" 0 0 0755 0644 u:object_r:system_lib_file:s0 set_perm_recursive "$MODPATH/system/lib64" 0 0 0755 0644 u:object_r:system_lib_file:s0 # If Huawei's Maple is enabled, system_server is created with a special way which is out of Zygisk's control diff --git a/zygiskd/Cargo.toml b/zygiskd/Cargo.toml index 956377a..8d7877d 100644 --- a/zygiskd/Cargo.toml +++ b/zygiskd/Cargo.toml @@ -19,12 +19,13 @@ memfd = "0.6" num_enum = "0.5" passfd = "0.1" proc-maps = "0.3" -ptrace-do = "0.1" + rustix = { version = "0.38", features = [ "fs", "process", "mount", "net", "thread"] } tokio = { version = "1.28", features = ["full"] } binder = { git = "https://github.com/Kernel-SU/binder_rs", rev = "c9f2b62d6a744fd2264056c638c1b061a6a2932d" } fuser = { git = "https://github.com/Dr-TSNG/fuser", default-features = false } +ptrace-do = { git = "https://github.com/5ec1cff/ptrace-do" } [profile.release] strip = true diff --git a/zygiskd/build.gradle.kts b/zygiskd/build.gradle.kts index 89c3ced..081cfc7 100644 --- a/zygiskd/build.gradle.kts +++ b/zygiskd/build.gradle.kts @@ -3,8 +3,6 @@ plugins { alias(libs.plugins.rust.android) } -val verName: String by rootProject.extra -val verCode: Int by rootProject.extra val minKsuVersion: Int by rootProject.extra val maxKsuVersion: Int by rootProject.extra val minMagiskVersion: Int by rootProject.extra @@ -18,14 +16,12 @@ cargo { module = "." libname = "zygiskd" targetIncludes = arrayOf("zygiskd") - targets = listOf("arm64", "x86_64") + targets = listOf("arm64", "arm", "x86", "x86_64") targetDirectory = "build/intermediates/rust" val isDebug = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") } profile = if (isDebug) "debug" else "release" exec = { spec, _ -> spec.environment("ANDROID_NDK_HOME", android.ndkDirectory.path) - spec.environment("VERSION_CODE", verCode) - spec.environment("VERSION_NAME", verName) spec.environment("MIN_KSU_VERSION", minKsuVersion) spec.environment("MAX_KSU_VERSION", maxKsuVersion) spec.environment("MIN_MAGISK_VERSION", minMagiskVersion) diff --git a/zygiskd/src/constants.rs b/zygiskd/src/constants.rs index 66bf57f..6e339ea 100644 --- a/zygiskd/src/constants.rs +++ b/zygiskd/src/constants.rs @@ -4,10 +4,8 @@ use konst::primitive::parse_i32; use konst::unwrap_ctx; use log::LevelFilter; use num_enum::TryFromPrimitive; +use crate::lp_select; -pub const VERSION_NAME: &str = env!("VERSION_NAME"); -pub const VERSION_CODE: &str = env!("VERSION_CODE"); -pub const VERSION_FULL: &str = concatcp!(VERSION_NAME, " (", VERSION_CODE, ")"); pub const MIN_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_KSU_VERSION"))); pub const MAX_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MAX_KSU_VERSION"))); pub const MIN_MAGISK_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_MAGISK_VERSION"))); @@ -18,19 +16,22 @@ pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Trace; pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Info; pub const PROP_CTL_RESTART: &str = "ctl.restart"; -pub const ZYGISK_LIBRARY: &str = "libzygisk.so"; pub const PATH_PCL: &str = "/system/etc/preloaded-classes"; -pub const PATH_SYSTEM_LIB: &str = "/system/lib64"; +pub const PATH_ZYGISK_LIB: &str = concatcp!(lp_select!("/system/lib", "/system/lib64"), "/libzygisk.so"); pub const PATH_WORK_DIR: &str = "/dev/zygisk"; // TODO: Replace with /debug_ramdisk/zygisk pub const PATH_PROP_OVERLAY: &str = concatcp!(PATH_WORK_DIR, "/module.prop"); -pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, "/cp.sock"); +pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, lp_select!("/cp32.sock", "/cp64.sock")); pub const PATH_FUSE_DIR: &str = concatcp!(PATH_WORK_DIR, "/fuse"); pub const PATH_FUSE_PCL: &str = concatcp!(PATH_FUSE_DIR, "/preloaded-classes"); pub const PATH_MODULES_DIR: &str = ".."; pub const PATH_MODULE_PROP: &str = "module.prop"; -pub const PATH_CP_BIN: &str = "bin/zygisk-cp"; +pub const PATH_CP_BIN32: &str = "bin/zygisk-cp32"; +pub const PATH_CP_BIN64: &str = "bin/zygisk-cp64"; +pub const PATH_PTRACE_BIN32: &str = "bin/zygisk-ptrace32"; +pub const PATH_PTRACE_BIN64: &str = "bin/zygisk-ptrace64"; + pub const STATUS_LOADED: &str = "😋 Zygisksu is loaded"; pub const STATUS_CRASHED: &str = "❌ Zygiskd has crashed"; diff --git a/zygiskd/src/fuse.rs b/zygiskd/src/fuse.rs index 785e615..5862a83 100644 --- a/zygiskd/src/fuse.rs +++ b/zygiskd/src/fuse.rs @@ -1,19 +1,18 @@ use std::cmp::min; use anyhow::{bail, Result}; -use std::ffi::{CString, OsStr}; +use std::ffi::OsStr; use std::{fs, thread}; +use std::io::Read; +use std::process::{Command, Stdio}; use std::sync::{mpsc, Mutex}; use std::time::{Duration, SystemTime}; use fuser::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, ReplyOpen, Request}; use libc::ENOENT; -use log::{debug, error, info}; -use proc_maps::{get_process_maps, MapRange, Pid}; -use ptrace_do::{RawProcess, TracedProcess}; +use log::{error, info}; use rustix::fs::UnmountFlags; use rustix::mount::{mount_bind, unmount}; use rustix::path::Arg; -use rustix::process::getpid; -use crate::{constants, dl}; +use crate::constants; use crate::utils::LateInit; pub struct DelegateFilesystem; @@ -38,9 +37,6 @@ const fn attr(inode: u64, size: u64, kind: FileType) -> FileAttr { } } -const ANDROID_LIBC: &str = "bionic/libc.so"; -const ANDROID_LIBDL: &str = "bionic/libdl.so"; - const INO_DIR: u64 = 1; const INO_PCL: u64 = 2; @@ -57,6 +53,66 @@ const ENTRIES: &[(u64, FileType, &str)] = &[ const TTL: Duration = Duration::from_secs(1); +fn ptrace_zygote64(pid: u32) -> Result<()> { + static LAST: Mutex = Mutex::new(0); + + let mut last = LAST.lock().unwrap(); + if *last == pid { + return Ok(()); + } + *last = pid; + let (sender, receiver) = mpsc::channel::<()>(); + + let worker = move || -> Result<()> { + let mut child = Command::new(constants::PATH_PTRACE_BIN64).stdout(Stdio::piped()).arg(format!("{}", pid)).spawn()?; + child.stdout.as_mut().unwrap().read_exact(&mut [0u8; 1])?; + info!("child attached"); + sender.send(())?; + let result = child.wait()?; + info!("ptrace64 process status {}", result); + Ok(()) + }; + + thread::spawn(move || { + if let Err(e) = worker() { + error!("Crashed: {:?}", e); + } + }); + + receiver.recv()?; + Ok(()) +} + +fn ptrace_zygote32(pid: u32) -> Result<()> { + static LAST: Mutex = Mutex::new(0); + + let mut last = LAST.lock().unwrap(); + if *last == pid { + return Ok(()); + } + *last = pid; + let (sender, receiver) = mpsc::channel::<()>(); + + let worker = move || -> Result<()> { + let mut child = Command::new(constants::PATH_PTRACE_BIN32).stdout(Stdio::piped()).arg(format!("{}", pid)).spawn()?; + child.stdout.as_mut().unwrap().read_exact(&mut [0u8; 1])?; + info!("child attached"); + sender.send(())?; + let result = child.wait()?; + info!("ptrace32 process status {}", result); + Ok(()) + }; + + thread::spawn(move || { + if let Err(e) = worker() { + error!("Crashed: {:?}", e); + } + }); + + receiver.recv()?; + Ok(()) +} + impl Filesystem for DelegateFilesystem { fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) { if parent != INO_DIR { @@ -84,8 +140,10 @@ impl Filesystem for DelegateFilesystem { let process = fs::read_to_string(process).unwrap(); let process = &process[..process.find('\0').unwrap()]; info!("Process {} is reading preloaded-classes", process); - if process == "zygote64" { - ptrace_zygote(pid).unwrap(); + match process { + "zygote64" => ptrace_zygote64(pid).unwrap(), + "zygote" => ptrace_zygote32(pid).unwrap(), + _ => (), } } reply.opened(0, 0); @@ -121,190 +179,6 @@ impl Filesystem for DelegateFilesystem { } } -fn find_module_for_pid(pid: Pid, library: &str) -> Result { - let maps = get_process_maps(pid)?; - for map in maps.into_iter() { - if let Some(p) = map.filename() { - if p.as_str()?.contains(library) { - return Ok(map); - } - } - } - bail!("Cannot find module {library} for pid {pid}"); -} - -fn find_remote_procedure( - pid: Pid, - library: &str, - local_addr: usize, -) -> Result { - let local_module = find_module_for_pid(getpid().as_raw_nonzero().get(), library)?; - debug!( - "Identifed local range {library} ({:?}) at {:x}", - local_module.filename(), - local_module.start() - ); - - let remote_module = find_module_for_pid(pid, library)?; - debug!( - "Identifed remote range {library} ({:?}) at {:x}", - remote_module.filename(), - remote_module.start() - ); - - Ok(local_addr - local_module.start() + remote_module.start()) -} - -fn ptrace_zygote(pid: u32) -> Result<()> { - static LAST: Mutex = Mutex::new(0); - - let mut last = LAST.lock().unwrap(); - if *last == pid { - return Ok(()); - } - *last = pid; - let (sender, receiver) = mpsc::channel::<()>(); - - let worker = move || -> Result<()> { - info!("Injecting into pid {}", pid); - let zygisk_lib = format!("{}/{}", constants::PATH_SYSTEM_LIB, constants::ZYGISK_LIBRARY); - let lib_dir = CString::new(constants::PATH_SYSTEM_LIB)?; - let zygisk_lib = CString::new(zygisk_lib)?; - let libc_base = find_module_for_pid(pid as i32, ANDROID_LIBC)?.start(); - let mmap_remote = find_remote_procedure( - pid as i32, - ANDROID_LIBC, - libc::mmap as usize, - )?; - let munmap_remote = find_remote_procedure( - pid as i32, - ANDROID_LIBC, - libc::munmap as usize, - )?; - let dlopen_remote = find_remote_procedure( - pid as i32, - ANDROID_LIBDL, - dl::android_dlopen_ext as usize, - )?; - let dlsym_remote = find_remote_procedure( - pid as i32, - ANDROID_LIBDL, - libc::dlsym as usize, - )?; - - let tracer = TracedProcess::attach(RawProcess::new(pid as i32))?; - sender.send(())?; - let frame = tracer.next_frame()?; - debug!("Waited for a frame"); - - // Map a buffer in the remote process - let mmap_params: [usize; 6] = [ - 0, - 0x1000, - (libc::PROT_READ | libc::PROT_WRITE) as usize, - (libc::MAP_ANONYMOUS | libc::MAP_PRIVATE) as usize, - 0, - 0, - ]; - let (regs, mut frame) = frame.invoke_remote( - mmap_remote, - libc_base, - &mmap_params, - )?; - let buf_addr = regs.return_value(); - debug!("Buffer addr: {:x}", buf_addr); - - // Find the address of __loader_android_create_namespace - let sym = CString::new("__loader_android_create_namespace")?; - frame.write_memory(buf_addr, sym.as_bytes_with_nul())?; - let (regs, mut frame) = frame.invoke_remote( - dlsym_remote, - libc_base, - &[libc::RTLD_DEFAULT as usize, buf_addr], - )?; - let android_create_namespace_remote = regs.return_value(); - debug!("__loader_android_create_namespace addr: {:x}", android_create_namespace_remote); - - // Create a linker namespace for remote process - frame.write_memory(buf_addr, zygisk_lib.as_bytes_with_nul())?; - frame.write_memory(buf_addr + 0x100, lib_dir.as_bytes_with_nul())?; - let ns_params: [usize; 7] = [ - buf_addr, // name - buf_addr + 0x100, // ld_library_path - 0, // default_library_path - dl::ANDROID_NAMESPACE_TYPE_SHARED as usize, // type - 0, // permitted_when_isolated_path - 0, // parent - dlopen_remote, // caller_addr - ]; - let (regs, mut frame) = frame.invoke_remote( - android_create_namespace_remote, - libc_base, - &ns_params, - )?; - let ns_addr = regs.return_value(); - debug!("Linker namespace addr: {:x}", ns_addr); - - // Load zygisk into remote process - let info = dl::AndroidDlextinfo { - flags: dl::ANDROID_DLEXT_USE_NAMESPACE, - reserved_addr: std::ptr::null_mut(), - reserved_size: 0, - relro_fd: 0, - library_fd: 0, - library_fd_offset: 0, - library_namespace: ns_addr as *mut _, - }; - let info = unsafe { - std::slice::from_raw_parts( - &info as *const _ as *const u8, - std::mem::size_of::(), - ) - }; - frame.write_memory(buf_addr + 0x200, info)?; - let (regs, mut frame) = frame.invoke_remote( - dlopen_remote, - libc_base, - &[buf_addr, libc::RTLD_NOW as usize, buf_addr + 0x200], - )?; - let handle = regs.return_value(); - debug!("Load zygisk into remote process: {:x}", handle); - - let entry = CString::new("entry")?; - frame.write_memory(buf_addr, entry.as_bytes_with_nul())?; - let (regs, frame) = frame.invoke_remote( - dlsym_remote, - libc_base, - &[handle, buf_addr], - )?; - let entry = regs.return_value(); - debug!("Call zygisk entry: {:x}", entry); - let (_, frame) = frame.invoke_remote( - entry, - libc_base, - &[handle], - )?; - - // Cleanup - let _ = frame.invoke_remote( - munmap_remote, - libc_base, - &[buf_addr], - )?; - debug!("Cleaned up"); - Ok(()) - }; - - thread::spawn(move || { - if let Err(e) = worker() { - error!("Crashed: {:?}", e); - } - }); - - receiver.recv()?; - Ok(()) -} - pub fn main() -> Result<()> { info!("Start zygisk fuse"); fs::create_dir(constants::PATH_WORK_DIR)?; diff --git a/zygiskd/src/main.rs b/zygiskd/src/main.rs index 3a98b4d..4bd032d 100644 --- a/zygiskd/src/main.rs +++ b/zygiskd/src/main.rs @@ -1,9 +1,7 @@ -#![feature(exclusive_range_pattern)] -#![allow(dead_code)] - mod constants; mod dl; mod fuse; +mod ptrace; mod root_impl; mod utils; mod watchdog; @@ -12,7 +10,6 @@ mod zygiskd; use std::future::Future; use anyhow::Result; - fn init_android_logger(tag: &str) { android_logger::init_once( android_logger::Config::default() @@ -32,8 +29,9 @@ fn start(name: &str) -> Result<()> { match name.trim_start_matches("zygisk-") { "wd" => async_start(watchdog::main())?, "fuse" => fuse::main()?, - "cp" => zygiskd::main()?, - _ => println!("Available commands: wd, fuse, cp"), + lp_select!("cp32", "cp64") => zygiskd::main()?, + lp_select!("ptrace32", "ptrace64") => ptrace::main()?, + _ => println!("Available commands: wd, fuse, cp, ptrace"), } Ok(()) } diff --git a/zygiskd/src/ptrace.rs b/zygiskd/src/ptrace.rs new file mode 100644 index 0000000..d91fb9f --- /dev/null +++ b/zygiskd/src/ptrace.rs @@ -0,0 +1,233 @@ +use log::{debug, info}; +use std::ffi::CString; +use std::env; +use std::io::Write; +use rustix::path::Arg; +use proc_maps::{get_process_maps, MapRange, Pid}; +use ptrace_do::{RawProcess, TracedProcess}; +use rustix::process::getpid; +use crate::{constants, lp_select}; +use anyhow::{bail, Result}; + +const ANDROID_LIBC: &str = "bionic/libc.so"; +const ANDROID_LIBDL: &str = "bionic/libdl.so"; + +fn find_module_for_pid(pid: Pid, library: &str) -> Result { + let maps = get_process_maps(pid)?; + for map in maps.into_iter() { + if let Some(p) = map.filename() { + if p.as_str()?.contains(library) { + return Ok(map); + } + } + } + bail!("Cannot find module {library} for pid {pid}"); +} + +fn find_remote_procedure( + pid: Pid, + library: &str, + local_addr: usize, +) -> Result { + let local_module = find_module_for_pid(getpid().as_raw_nonzero().get(), library)?; + debug!( + "Identifed local range {library} ({:?}) at {:x}", + local_module.filename(), + local_module.start() + ); + + let remote_module = find_module_for_pid(pid, library)?; + debug!( + "Identifed remote range {library} ({:?}) at {:x}", + remote_module.filename(), + remote_module.start() + ); + + Ok(local_addr - local_module.start() + remote_module.start()) +} + +fn ptrace_zygote(pid: u32) -> Result<()> { + info!("Injecting into pid {}", pid); + let zygisk_lib = CString::new(constants::PATH_ZYGISK_LIB)?; + let libc_base = find_module_for_pid(pid as i32, ANDROID_LIBC)?.start(); + let mmap_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBC, + libc::mmap as usize, + )?; + let munmap_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBC, + libc::munmap as usize, + )?; + let dlopen_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBDL, + libc::dlopen as usize, + )?; + let dlsym_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBDL, + libc::dlsym as usize, + )?; + let errno_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBC, + libc::__errno as usize, + )?; + let dlerror_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBDL, + libc::dlerror as usize, + )?; + let strlen_remote = find_remote_procedure( + pid as i32, + ANDROID_LIBC, + libc::strlen as usize, + )?; + + let tracer = TracedProcess::attach(RawProcess::new(pid as i32))?; + std::io::stdout().write(b"1")?; + info!("attached process {}", pid); + std::io::stdout().flush()?; + let frame = tracer.next_frame()?; + debug!("Waited for a frame"); + + // Map a buffer in the remote process + debug!("remote mmap addr {:x}", mmap_remote); + let mmap_params: [usize; 6] = [ + 0, + 0x1000, + (libc::PROT_READ | libc::PROT_WRITE) as usize, + (libc::MAP_ANONYMOUS | libc::MAP_PRIVATE) as usize, + 0, + 0, + ]; + let mut arr: Vec = Vec::new(); + for p in mmap_params { + arr.extend_from_slice(&p.to_le_bytes()); + } + arr.as_slice(); + let (regs, mut frame) = frame.invoke_remote( + mmap_remote, + libc_base, + &mmap_params, + )?; + let buf_addr = regs.return_value(); + debug!("remote stopped at addr {:x}", regs.program_counter()); + if regs.program_counter() != libc_base { + let data = std::mem::MaybeUninit::::uninit(); + let siginfo = unsafe { + libc::ptrace(libc::PTRACE_GETSIGINFO, pid, 0, &data); + data.assume_init() + }; + bail!( + "stopped at unexpected addr {:x} signo {} si_code {} si_addr {:?}", + regs.program_counter(), + siginfo.si_signo, + siginfo.si_code, + unsafe { siginfo.si_addr() }, + ); + } + if buf_addr == usize::MAX { + debug!("errno remote {:x}", errno_remote); + let (regs, frame) = frame.invoke_remote( + errno_remote, + libc_base, + &[], + )?; + debug!("errno called"); + if regs.program_counter() != libc_base { + bail!("stopped at unexpected addr {:x} when getting errno", regs.program_counter()); + } + let err_addr = regs.return_value(); + let mut buf = [0u8; 4]; + frame.read_memory_mut(err_addr, &mut buf)?; + let err = i32::from_le_bytes(buf); + bail!("remote failed with {}", err); + } + debug!("Buffer addr: {:x}", buf_addr); + + // Load zygisk into remote process + frame.write_memory(buf_addr, zygisk_lib.as_bytes_with_nul())?; + let (regs, mut frame) = frame.invoke_remote( + dlopen_remote, + libc_base, + &[buf_addr, libc::RTLD_NOW as usize], + )?; + let handle = regs.return_value(); + debug!("Load zygisk into remote process: {:x}", handle); + if regs.program_counter() != libc_base { + let data = std::mem::MaybeUninit::::uninit(); + let siginfo = unsafe { + libc::ptrace(libc::PTRACE_GETSIGINFO, pid, 0, &data); + data.assume_init() + }; + bail!( + "stopped at unexpected addr {:x} signo {} si_code {} si_addr {:?}", + regs.program_counter(), + siginfo.si_signo, + siginfo.si_code, + unsafe { siginfo.si_addr() }, + ); + } + if handle == 0 { + debug!("got handle 0"); + let (regs, frame) = frame.invoke_remote( + dlerror_remote, + libc_base, + &[], + )?; + let err_addr = regs.return_value(); + if err_addr == 0 { + bail!("dlerror err addr 0"); + } + debug!("err addr {:x}", err_addr); + let (regs, frame) = frame.invoke_remote( + strlen_remote, + libc_base, + &[err_addr], + )?; + let len = regs.return_value(); + if len == 0 { + bail!("dlerror len 0"); + } + debug!("err len {}", len); + let mut buf = vec![0u8; len]; + frame.read_memory_mut(err_addr, buf.as_mut_slice())?; + bail!("err {:?}", buf); + } + + let entry = CString::new("entry")?; + frame.write_memory(buf_addr, entry.as_bytes_with_nul())?; + let (regs, frame) = frame.invoke_remote( + dlsym_remote, + libc_base, + &[handle, buf_addr], + )?; + let entry = regs.return_value(); + debug!("Call zygisk entry: {:x}", entry); + let (_, frame) = frame.invoke_remote( + entry, + libc_base, + &[handle], + )?; + + // Cleanup + let _ = frame.invoke_remote( + munmap_remote, + libc_base, + &[buf_addr], + )?; + debug!("Cleaned up"); + Ok(()) +} + +pub fn main() -> Result<()> { + info!("Start zygisk ptrace"); + let args: Vec = env::args().collect(); + let pid = args[1].parse::().unwrap(); + info!("ptracing {} pid {}", lp_select!("zygote32", "zygote64"), pid); + ptrace_zygote(pid)?; + Ok(()) +} diff --git a/zygiskd/src/root_impl/kernelsu.rs b/zygiskd/src/root_impl/kernelsu.rs index 3139314..e92163c 100644 --- a/zygiskd/src/root_impl/kernelsu.rs +++ b/zygiskd/src/root_impl/kernelsu.rs @@ -26,7 +26,7 @@ pub fn get_kernel_su() -> Option { match version { 0 => None, MIN_KSU_VERSION..=MAX_KSU_VERSION => Some(Version::Supported), - 1..MIN_KSU_VERSION => Some(Version::TooOld), + 1..=MIN_KSU_VERSION => Some(Version::TooOld), _ => Some(Version::Abnormal), } } diff --git a/zygiskd/src/utils.rs b/zygiskd/src/utils.rs index d553d83..481d36f 100644 --- a/zygiskd/src/utils.rs +++ b/zygiskd/src/utils.rs @@ -8,6 +8,17 @@ use std::sync::OnceLock; use rustix::net::{AddressFamily, bind_unix, listen, socket, SocketAddrUnix, SocketType}; use rustix::thread::gettid; +#[cfg(target_pointer_width = "64")] +#[macro_export] +macro_rules! lp_select { + ($lp32:expr, $lp64:expr) => { $lp64 }; +} +#[cfg(target_pointer_width = "32")] +#[macro_export] +macro_rules! lp_select { + ($lp32:expr, $lp64:expr) => { $lp32 }; +} + #[cfg(debug_assertions)] #[macro_export] macro_rules! debug_select { diff --git a/zygiskd/src/watchdog.rs b/zygiskd/src/watchdog.rs index cbd9b23..cd2f38e 100644 --- a/zygiskd/src/watchdog.rs +++ b/zygiskd/src/watchdog.rs @@ -36,11 +36,6 @@ async fn run() -> Result<()> { Ok(()) } -fn spawn_fuse() -> Result<()> { - Command::new("bin/zygisk-fuse").spawn()?; - Ok(()) -} - fn check_permission() -> Result<()> { info!("Check permission"); let uid = getuid(); @@ -116,14 +111,22 @@ async fn spawn_daemon() -> Result<()> { let mut lives = 5; loop { let mut futures = FuturesUnordered::>>>>::new(); - let daemon = Command::new(constants::PATH_CP_BIN).spawn()?; - let daemon_pid = daemon.id().unwrap(); - - async fn daemon_holder(mut daemon: Child) -> Result<()> { + let mut child_ids = vec![]; + let daemon32 = Command::new(constants::PATH_CP_BIN32).arg("daemon").spawn(); + let daemon64 = Command::new(constants::PATH_CP_BIN64).arg("daemon").spawn(); + async fn spawn_daemon(mut daemon: Child) -> Result<()> { let result = daemon.wait().await?; - bail!("Daemon process {} died: {}", daemon.id().unwrap(), result); + log::error!("Daemon process {} died: {}", daemon.id().unwrap(), result); + Ok(()) + } + if let Ok(it) = daemon32 { + child_ids.push(it.id().unwrap()); + futures.push(Box::pin(spawn_daemon(it))); + } + if let Ok(it) = daemon64 { + child_ids.push(it.id().unwrap()); + futures.push(Box::pin(spawn_daemon(it))); } - futures.push(Box::pin(daemon_holder(daemon))); async fn binder_listener() -> Result<()> { let mut binder = loop { @@ -150,8 +153,10 @@ async fn spawn_daemon() -> Result<()> { error!("{}", e); } - debug!("Killing child process {}", daemon_pid); - let _ = kill_process(Pid::from_raw(daemon_pid as i32).unwrap(), Signal::Kill); + for child in child_ids { + debug!("Killing child process {}", child); + let _ = kill_process(Pid::from_raw(child as i32).unwrap(), Signal::Kill); + } lives -= 1; if lives == 0 { diff --git a/zygiskd/src/zygiskd.rs b/zygiskd/src/zygiskd.rs index dcc43e5..2df1ef3 100644 --- a/zygiskd/src/zygiskd.rs +++ b/zygiskd/src/zygiskd.rs @@ -1,8 +1,8 @@ use std::ffi::c_void; use crate::constants::{DaemonSocketAction, ProcessFlags}; use crate::utils::UnixStreamExt; -use crate::{constants, dl, root_impl, utils}; -use anyhow::Result; +use crate::{constants, dl, lp_select, root_impl, utils}; +use anyhow::{bail, Result}; use passfd::FdPassingExt; use std::sync::Arc; use std::thread; @@ -32,11 +32,11 @@ pub fn main() -> Result<()> { log::info!("Start zygisk companion"); set_parent_process_death_signal(Some(Signal::Kill))?; - let arch = utils::get_property("ro.product.cpu.abi")?; + let arch = get_arch()?; log::debug!("Daemon architecture: {arch}"); log::info!("Load modules"); - let modules = load_modules(&arch)?; + let modules = load_modules(arch)?; let context = Context { modules, @@ -60,6 +60,17 @@ pub fn main() -> Result<()> { Ok(()) } +fn get_arch() -> Result<&'static str> { + let system_arch = utils::get_property("ro.product.cpu.abi")?; + if system_arch.contains("arm") { + return Ok(lp_select!("armeabi-v7a", "arm64-v8a")); + } + if system_arch.contains("x86") { + return Ok(lp_select!("x86", "x86_64")); + } + bail!("Unsupported system architecture: {}", system_arch); +} + fn load_modules(arch: &str) -> Result> { let mut modules = Vec::new(); let dir = match fs::read_dir(constants::PATH_MODULES_DIR) {