From f27680609680b36f1a152782953b8afaca301c24 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Mon, 2 Feb 2026 18:43:13 +0100 Subject: [PATCH] fix(native): block attestation leak when interceptor service is dead When the Java interceptor process dies, callback->transact() returns DEAD_OBJECT but the code fell through to the real keystore, exposing genuine TEE state to requesting apps. Add pingBinder() liveness check on pre-transact failure. If the interceptor is confirmed dead, return DEAD_OBJECT to the caller instead of forwarding to real hardware. Apps see a transient service error rather than the actual device attestation state. --- app/src/main/cpp/binder_interceptor.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) 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