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"