From 34ad97366e6b8906fb34866fa39a0357b4693b84 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Sat, 7 Feb 2026 00:47:04 +0100 Subject: [PATCH] feat(module): add supervisor daemon with leak-safe restart and lifecycle scripts Fork-based supervisor ensures the interceptor process survives crashes. pingBinder() liveness check on pre-transact returns DEAD_OBJECT to callers when interceptor is down, preventing real TEE state from leaking during the restart window. action.sh clears persistent key storage via KSU Action button. uninstall.sh kills daemon processes and removes module artifacts while preserving target.txt and keybox configuration. --- app/build.gradle.kts | 2 +- app/src/main/cpp/CMakeLists.txt | 3 ++ app/src/main/cpp/binder_interceptor.cpp | 16 +++++-- app/src/main/cpp/supervisor.cpp | 57 +++++++++++++++++++++++++ module/action.sh | 11 +++++ module/customize.sh | 3 ++ module/service.sh | 10 +---- module/uninstall.sh | 11 +++++ 8 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 app/src/main/cpp/supervisor.cpp create mode 100644 module/action.sh create mode 100644 module/uninstall.sh diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f2ad4e1..06bef23 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -116,7 +116,7 @@ androidComponents { ) ) { into("lib") // Place them in the 'lib' subfolder of the staging directory. - include("**/libinject.so", "**/libTEESimulator.so") + include("**/libinject.so", "**/libTEESimulator.so", "**/libsupervisor.so") } // Now, copy and process the files from 'module' directory. diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 30cd7f3..e32e6b2 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -22,6 +22,9 @@ add_executable(libinject.so inject/main.cpp inject/utils.cpp) target_include_directories(libinject.so PUBLIC include) target_link_libraries(libinject.so PRIVATE lsplt_static) +add_executable(libsupervisor.so supervisor.cpp) +target_link_libraries(libsupervisor.so PRIVATE log) + add_library(${CMAKE_PROJECT_NAME} SHARED binder_interceptor.cpp) target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC external/linux-kernel/include include) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE binder lsplt_static utils) diff --git a/app/src/main/cpp/binder_interceptor.cpp b/app/src/main/cpp/binder_interceptor.cpp index bc2b2b5..ef84319 100644 --- a/app/src/main/cpp/binder_interceptor.cpp +++ b/app/src/main/cpp/binder_interceptor.cpp @@ -592,9 +592,16 @@ bool BinderInterceptor::processInterceptedTransaction(uint64_t tx_id, sptransact(intercept::kPreTransact, pre_req, &pre_resp) != OK) { - LOGW("[TX_ID: %" PRIu64 "] Pre-transaction callback failed. Forwarding original call.", tx_id); - return false; // Callback failed, proceed as if not intercepted + status_t pre_status = callback->transact(intercept::kPreTransact, pre_req, &pre_resp); + if (pre_status != OK) { + // Block when interceptor is dead to prevent privacy leak to third-party apps + if (callback->pingBinder() != OK) { + LOGE("[TX_ID: %" PRIu64 "] Interceptor DEAD. Blocking to prevent attestation leak.", tx_id); + result = DEAD_OBJECT; + return true; + } + LOGW("[TX_ID: %" PRIu64 "] Pre-transaction callback failed (not dead). Forwarding.", tx_id); + return false; } int32_t action = pre_resp.readInt32(); @@ -647,7 +654,8 @@ bool BinderInterceptor::processInterceptedTransaction(uint64_t tx_id, sptransact(intercept::kPostTransact, post_req, &post_resp) == OK) { + status_t post_status = callback->transact(intercept::kPostTransact, post_req, &post_resp); + if (post_status == OK) { int32_t post_action = post_resp.readInt32(); if (post_action == intercept::kActionOverrideReply && reply) { result = post_resp.readInt32(); // Read new status diff --git a/app/src/main/cpp/supervisor.cpp b/app/src/main/cpp/supervisor.cpp new file mode 100644 index 0000000..ada8000 --- /dev/null +++ b/app/src/main/cpp/supervisor.cpp @@ -0,0 +1,57 @@ +// Fork-based supervisor for instant daemon restart +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile sig_atomic_t should_exit = 0; + +static void signal_handler(int sig) { + should_exit = 1; +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "Usage: %s [args...]\n", argv[0]); + return 1; + } + + // Forward termination signals to exit cleanly + signal(SIGTERM, signal_handler); + signal(SIGINT, signal_handler); + + const char *daemon_path = argv[1]; + char **daemon_argv = &argv[1]; + + while (!should_exit) { + pid_t pid = fork(); + + if (pid < 0) { + perror("fork failed"); + usleep(100000); // 100ms backoff on fork failure + continue; + } + + if (pid == 0) { + // Child: become the daemon + prctl(PR_SET_PDEATHSIG, SIGKILL); // Die if parent dies + execv(daemon_path, daemon_argv); + perror("execv failed"); + _exit(127); + } + + // Parent: wait for child to exit + int status; + waitpid(pid, &status, 0); + + if (should_exit) break; + + // Instant restart - no delay + } + + return 0; +} diff --git a/module/action.sh b/module/action.sh new file mode 100644 index 0000000..00ae7bf --- /dev/null +++ b/module/action.sh @@ -0,0 +1,11 @@ +#!/system/bin/sh +MODDIR=${0%/*} +CONFIG_DIR=/data/adb/tricky_store + +if [ -d "$CONFIG_DIR/persistent_keys" ]; then + rm -rf "$CONFIG_DIR/persistent_keys" + mkdir -p "$CONFIG_DIR/persistent_keys" + echo "Persistent key storage cleared" +else + echo "No persistent key storage found" +fi diff --git a/module/customize.sh b/module/customize.sh index 373cd42..5009546 100644 --- a/module/customize.sh +++ b/module/customize.sh @@ -67,10 +67,13 @@ ui_print "" ui_print "- Extracting $ARCH libraries" install_file "lib/$ABI_DIR/libTEESimulator.so" "$MODPATH" install_file "lib/$ABI_DIR/libinject.so" "$MODPATH" +install_file "lib/$ABI_DIR/libsupervisor.so" "$MODPATH" ui_print "" mv "$MODPATH/libinject.so" "$MODPATH/inject" +mv "$MODPATH/libsupervisor.so" "$MODPATH/supervisor" chmod 755 "$MODPATH/inject" +chmod 755 "$MODPATH/supervisor" # --- Configuration Files --- if [ ! -d "$CONFIG_DIR" ]; then diff --git a/module/service.sh b/module/service.sh index b2a3562..49fe888 100644 --- a/module/service.sh +++ b/module/service.sh @@ -1,11 +1,5 @@ -DEBUG=false - MODDIR=${0%/*} - cd $MODDIR -while true; do - ./daemon "$MODDIR" || exit 1 - # ensure keystore initialized - sleep 2 -done & +# Fork-based supervisor for instant restart +./supervisor ./daemon "$MODDIR" & diff --git a/module/uninstall.sh b/module/uninstall.sh new file mode 100644 index 0000000..faf1ddc --- /dev/null +++ b/module/uninstall.sh @@ -0,0 +1,11 @@ +#!/system/bin/sh +MODDIR=${0%/*} +CONFIG_DIR=/data/adb/tricky_store + +# Kill daemon and supervisor +for pid in $(pidof TEESimulator) $(pidof supervisor) $(pidof daemon); do + kill -9 "$pid" 2>/dev/null +done + +rm -rf "$CONFIG_DIR/persistent_keys" +rm -f "$CONFIG_DIR/tee_status.txt"