fix(interception): restore G2 binder overhead mitigations from pre-PR157
Commitb6f9d7bintroduced G2-specific fixes (ratio dropped from 5.00x to 2.10x) that were lost when resetting to upstream PR #157 at94c8e5b. Restores: try-catch safety in BinderInterceptor.onTransact, shouldPatch early-exit in getKeyEntry post-transact, safe parcel reads (!! to ?:) at 6 sites, teeResponses cache population in generateKey/importKey post-transact, uncaught exception handler in App.kt, and removes the pingBinder liveness check that added ~1.8x overhead per pre-transact.
This commit is contained in:
@@ -612,14 +612,8 @@ bool BinderInterceptor::processInterceptedTransaction(uint64_t tx_id, sp<BBinder
|
||||
Parcel pre_req, pre_resp;
|
||||
writeTransactionData(pre_req, tx_id, target, code, flags, request);
|
||||
|
||||
status_t pre_status = callback->transact(intercept::kPreTransact, pre_req, &pre_resp);
|
||||
if (pre_status != OK) {
|
||||
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);
|
||||
if (callback->transact(intercept::kPreTransact, pre_req, &pre_resp) != OK) {
|
||||
LOGW("[TX_ID: %" PRIu64 "] Pre-transaction callback failed. Forwarding original call.", tx_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,11 @@ object App {
|
||||
fun main(args: Array<String>) {
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+3
@@ -289,6 +289,9 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
|
||||
callingPid,
|
||||
)
|
||||
|
||||
if (!ConfigurationManager.shouldPatch(callingUid))
|
||||
return TransactionResult.SkipTransaction
|
||||
|
||||
runCatching {
|
||||
val response = reply.readTypedObject(KeyEntryResponse.CREATOR)!!
|
||||
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
||||
|
||||
+34
-14
@@ -82,7 +82,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}]"
|
||||
)
|
||||
@@ -140,6 +141,10 @@ class KeyMintSecurityLevelInterceptor(
|
||||
metadata.authorizations =
|
||||
InterceptorUtils.patchAuthorizations(metadata.authorizations, callingUid)
|
||||
patchedChains[keyId] = newChain
|
||||
teeResponses[keyId] = KeyEntryResponse().apply {
|
||||
this.metadata = metadata
|
||||
iSecurityLevel = original
|
||||
}
|
||||
SystemLogger.debug("Cached patched certificate chain for imported key $keyId.")
|
||||
return InterceptorUtils.createTypedObjectReply(metadata)
|
||||
}
|
||||
@@ -148,8 +153,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)
|
||||
@@ -157,7 +164,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}"
|
||||
)
|
||||
@@ -190,9 +198,6 @@ class KeyMintSecurityLevelInterceptor(
|
||||
val metadata: KeyMetadata =
|
||||
reply.readTypedObject(KeyMetadata.CREATOR)
|
||||
?: return TransactionResult.SkipTransaction
|
||||
KeyMintAttestation(
|
||||
metadata.authorizations?.map { it.keyParameter }?.toTypedArray() ?: emptyArray()
|
||||
)
|
||||
val originalChain =
|
||||
CertificateHelper.getCertificateChain(metadata)
|
||||
?: return TransactionResult.SkipTransaction
|
||||
@@ -201,16 +206,23 @@ 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 =
|
||||
InterceptorUtils.patchAuthorizations(metadata.authorizations, callingUid)
|
||||
|
||||
// We must clean up cached generated keys before storing the patched chain
|
||||
cleanupKeyData(keyId)
|
||||
patchedChains[keyId] = newChain
|
||||
|
||||
teeResponses[keyId] = KeyEntryResponse().apply {
|
||||
this.metadata = metadata
|
||||
iSecurityLevel = original
|
||||
}
|
||||
|
||||
SystemLogger.debug(
|
||||
"Cached patched certificate chain for $keyId. (${key.alias} [${key.domain}, ${key.nspace}])"
|
||||
)
|
||||
@@ -232,9 +244,9 @@ class KeyMintSecurityLevelInterceptor(
|
||||
data: Parcel,
|
||||
): TransactionResult {
|
||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||
?: return TransactionResult.ContinueAndSkipPost
|
||||
|
||||
// Resolve key descriptor to a generated key via nspace (KEY_ID) or alias (APP).
|
||||
val resolvedEntry: Map.Entry<KeyIdentifier, GeneratedKeyInfo>? =
|
||||
when (keyDescriptor.domain) {
|
||||
Domain.KEY_ID -> {
|
||||
@@ -414,13 +426,15 @@ class KeyMintSecurityLevelInterceptor(
|
||||
private fun handleGenerateKey(txId: Long, callingUid: Int, callingPid: Int, data: Parcel): TransactionResult {
|
||||
return runCatching {
|
||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||
?: return@runCatching TransactionResult.ContinueAndSkipPost
|
||||
val attestationKey = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||
SystemLogger.debug(
|
||||
"Handling generateKey ${keyDescriptor.alias}, attestKey=${attestationKey?.alias}"
|
||||
)
|
||||
|
||||
val params = data.createTypedArray(KeyParameter.CREATOR)!!
|
||||
val params = data.createTypedArray(KeyParameter.CREATOR)
|
||||
?: return@runCatching TransactionResult.ContinueAndSkipPost
|
||||
val parsedParams = KeyMintAttestation(params)
|
||||
|
||||
val challenge = parsedParams.attestationChallenge
|
||||
@@ -478,10 +492,16 @@ class KeyMintSecurityLevelInterceptor(
|
||||
|
||||
val isAuto = ConfigurationManager.isAutoMode(callingUid)
|
||||
|
||||
val isStrongBox = securityLevel == SecurityLevel.STRONGBOX
|
||||
|
||||
when {
|
||||
forceGenerate -> doSoftwareGeneration(
|
||||
callingUid, keyDescriptor, attestationKey, parsedParams, isAttestKeyRequest
|
||||
)
|
||||
// StrongBox before TEE-race: broken StrongBox HALs must never reach raceTeePatch
|
||||
isAuto && isStrongBox -> doSoftwareGeneration(
|
||||
callingUid, keyDescriptor, attestationKey, parsedParams, isAttestKeyRequest
|
||||
)
|
||||
isAuto && !teeFunctional -> raceTeePatch(
|
||||
callingUid, keyDescriptor, attestationKey, params, parsedParams, isAttestKeyRequest
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user