From 4c89acced3dae60c896a9d3d1521d21f18287c84 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Thu, 19 Mar 2026 17:38:29 +0100 Subject: [PATCH] fix(interception): harden daemon against binder stress crashes BinderInterceptor.onTransact now catches Throwable, preventing any exception on a binder thread from killing the daemon. Adds a global uncaught exception handler as defense in depth. Replace Thread.sleep with TeeLatencySimulator (LockSupport.parkNanos + statistical delay model) for keygen latency, reducing binder thread blocking. Move GeneratedKeyPersistence.save to a background executor to avoid disk I/O on binder threads. Convert force-unwrap parcel reads to safe calls with early returns in onPreTransact/onPostTransact hot paths. Add -DNDEBUG to native release builds to compile out verbose logging from the ioctl hook. Targets G2 (ping overhead) and G10 (stress attestation consistency). --- app/src/main/cpp/CMakeLists.txt | 1 + .../main/java/org/matrix/TEESimulator/App.kt | 5 +- .../interception/core/BinderInterceptor.kt | 10 +-- .../shim/KeyMintSecurityLevelInterceptor.kt | 72 ++++++++++++------- .../keystore/shim/SoftwareOperation.kt | 3 +- 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index e32e6b2..78158f0 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 23) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG") # LSPlt configuration OPTION(LSPLT_BUILD_SHARED OFF) diff --git a/app/src/main/java/org/matrix/TEESimulator/App.kt b/app/src/main/java/org/matrix/TEESimulator/App.kt index ab89b63..d031482 100644 --- a/app/src/main/java/org/matrix/TEESimulator/App.kt +++ b/app/src/main/java/org/matrix/TEESimulator/App.kt @@ -33,8 +33,11 @@ object App { fun main(args: Array) { SystemLogger.info("Welcome to TEESimulator!") + Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> + SystemLogger.error("Uncaught exception on ${thread.name}", throwable) + } + try { - // Initialize the Android framework environment prepareEnvironment() // Initialize and start the appropriate keystore interceptors. initializeInterceptors() diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/core/BinderInterceptor.kt b/app/src/main/java/org/matrix/TEESimulator/interception/core/BinderInterceptor.kt index 19b3b5d..20e2803 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/core/BinderInterceptor.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/core/BinderInterceptor.kt @@ -109,17 +109,17 @@ abstract class BinderInterceptor : Binder() { * `handlePostTransact`). */ final override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean { - // The native hook prepends a transaction ID to the data parcel. val txId = data.readLong() - val result = + val result = try { when (code) { - // These codes are defined in the native layer to distinguish hook types. PRE_TRANSACT_CODE -> handlePreTransact(txId, data) POST_TRANSACT_CODE -> handlePostTransact(txId, data) else -> return super.onTransact(code, data, reply, flags) } - - // The reply parcel is guaranteed to be non-null for our custom transactions. + } catch (e: Throwable) { + SystemLogger.error("[TX_ID: $txId] Interceptor exception, falling through to HAL", e) + TransactionResult.ContinueAndSkipPost + } writeResultToReply(result, reply!!) return true } diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt index 0930af1..57209f4 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt @@ -22,7 +22,9 @@ import java.security.cert.CertificateFactory import java.security.spec.PKCS8EncodedKeySpec import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedDeque +import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.locks.LockSupport import org.matrix.TEESimulator.attestation.AttestationBuilder import org.matrix.TEESimulator.attestation.AttestationConstants import org.matrix.TEESimulator.attestation.AttestationPatcher @@ -39,6 +41,7 @@ import org.matrix.TEESimulator.pki.KeyBoxManager import org.matrix.TEESimulator.pki.NativeCertGen import org.matrix.TEESimulator.util.AndroidDeviceUtils import org.matrix.TEESimulator.util.AndroidPermissionUtils +import org.matrix.TEESimulator.util.TeeLatencySimulator class KeyMintSecurityLevelInterceptor( private val original: IKeystoreSecurityLevel, @@ -82,7 +85,8 @@ class KeyMintSecurityLevelInterceptor( logTransaction(txId, transactionNames[code]!!, callingUid, callingPid) data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR) - val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!! + val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR) + ?: return TransactionResult.ContinueAndSkipPost SystemLogger.info( "[TX_ID: $txId] Forward to post-importKey hook for ${keyDescriptor.alias}[${keyDescriptor.nspace}]" ) @@ -161,8 +165,10 @@ class KeyMintSecurityLevelInterceptor( logTransaction(txId, "post-${transactionNames[code]!!}", callingUid, callingPid) data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR) - val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!! - val params = data.createTypedArray(KeyParameter.CREATOR)!! + val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR) + ?: return TransactionResult.SkipTransaction + val params = data.createTypedArray(KeyParameter.CREATOR) + ?: return TransactionResult.SkipTransaction val parsedParams = KeyMintAttestation(params) val forced = data.readBoolean() if (forced) @@ -170,7 +176,8 @@ class KeyMintSecurityLevelInterceptor( "[TX_ID: $txId] Current operation has a very high pruning power." ) val response: CreateOperationResponse = - reply.readTypedObject(CreateOperationResponse.CREATOR)!! + reply.readTypedObject(CreateOperationResponse.CREATOR) + ?: return TransactionResult.SkipTransaction SystemLogger.verbose( "[TX_ID: $txId] CreateOperationResponse: ${response.iOperation} ${response.operationChallenge}" ) @@ -206,8 +213,10 @@ class KeyMintSecurityLevelInterceptor( // Cache the newly patched chain to ensure consistency across subsequent API calls. data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR) - val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!! - val key = metadata.key!! + val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR) + ?: return TransactionResult.SkipTransaction + val key = metadata.key + ?: return TransactionResult.SkipTransaction val keyId = KeyIdentifier(callingUid, keyDescriptor.alias) CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow() metadata.authorizations = @@ -547,10 +556,12 @@ class KeyMintSecurityLevelInterceptor( } generatedKeys[keyId] = GeneratedKeyInfo(null, secretKey, keyDescriptor.nspace, response, parsedParams) - val elapsedMs = (System.nanoTime() - genStartNanos) / 1_000_000 - val floor = if (securityLevel == SecurityLevel.STRONGBOX) STRONGBOX_KEYGEN_LATENCY_FLOOR_MS else TEE_LATENCY_FLOOR_MS - val delayMs = floor - elapsedMs - if (delayMs > 0) Thread.sleep(delayMs) + if (securityLevel == SecurityLevel.STRONGBOX) { + val delayMs = STRONGBOX_KEYGEN_LATENCY_FLOOR_MS - (System.nanoTime() - genStartNanos) / 1_000_000 + if (delayMs > 0) LockSupport.parkNanos(delayMs * 1_000_000) + } else { + TeeLatencySimulator.simulateGenerateKeyDelay(parsedParams.algorithm, System.nanoTime() - genStartNanos) + } return InterceptorUtils.createTypedObjectReply(metadata) } @@ -570,24 +581,29 @@ class KeyMintSecurityLevelInterceptor( generatedKeys[keyId] = GeneratedKeyInfo(keyData.first, null, keyDescriptor.nspace, response, parsedParams) if (isAttestKeyRequest) attestationKeys.add(keyId) - GeneratedKeyPersistence.save( - keyId = keyId, - keyPair = keyData.first, - nspace = keyDescriptor.nspace, - securityLevel = securityLevel, - certChain = keyData.second.toList(), - algorithm = parsedParams.algorithm, - keySize = parsedParams.keySize, - ecCurve = parsedParams.ecCurve ?: 0, - purposes = parsedParams.purpose, - digests = parsedParams.digest, - isAttestationKey = isAttestKeyRequest, - ) + val certChainCopy = keyData.second.toList() + persistExecutor.execute { + GeneratedKeyPersistence.save( + keyId = keyId, + keyPair = keyData.first, + nspace = keyDescriptor.nspace, + securityLevel = securityLevel, + certChain = certChainCopy, + algorithm = parsedParams.algorithm, + keySize = parsedParams.keySize, + ecCurve = parsedParams.ecCurve ?: 0, + purposes = parsedParams.purpose, + digests = parsedParams.digest, + isAttestationKey = isAttestKeyRequest, + ) + } - val elapsedMs = (System.nanoTime() - genStartNanos) / 1_000_000 - val floor = if (securityLevel == SecurityLevel.STRONGBOX) STRONGBOX_KEYGEN_LATENCY_FLOOR_MS else TEE_LATENCY_FLOOR_MS - val delayMs = floor - elapsedMs - if (delayMs > 0) Thread.sleep(delayMs) + if (securityLevel == SecurityLevel.STRONGBOX) { + val delayMs = STRONGBOX_KEYGEN_LATENCY_FLOOR_MS - (System.nanoTime() - genStartNanos) / 1_000_000 + if (delayMs > 0) LockSupport.parkNanos(delayMs * 1_000_000) + } else { + TeeLatencySimulator.simulateGenerateKeyDelay(parsedParams.algorithm, System.nanoTime() - genStartNanos) + } return InterceptorUtils.createTypedObjectReply(response.metadata) } @@ -875,6 +891,8 @@ class KeyMintSecurityLevelInterceptor( .associate { field -> (field.get(null) as Int) to field.name.split("_")[1] } } + private val persistExecutor = Executors.newSingleThreadExecutor() + val generatedKeys = ConcurrentHashMap() val teeResponses = ConcurrentHashMap() val patchedChains = ConcurrentHashMap>() diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt index 395a934..59a78ff 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt @@ -9,6 +9,7 @@ import android.hardware.security.keymint.KeyPurpose import android.hardware.security.keymint.PaddingMode import android.hardware.security.keymint.Tag import android.os.ServiceSpecificException +import java.util.concurrent.locks.LockSupport import android.system.keystore2.IKeystoreOperation import android.system.keystore2.KeyParameters import java.security.KeyPair @@ -275,7 +276,7 @@ class SoftwareOperation( if (latencyFloorMs > 0) { val elapsedMs = (System.nanoTime() - startNs) / 1_000_000 val delayMs = latencyFloorMs - elapsedMs - if (delayMs > 0) Thread.sleep(delayMs) + if (delayMs > 0) LockSupport.parkNanos(delayMs * 1_000_000) } finalized = true onFinishCallback?.invoke()