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;
|
Parcel pre_req, pre_resp;
|
||||||
writeTransactionData(pre_req, tx_id, target, code, flags, request);
|
writeTransactionData(pre_req, tx_id, target, code, flags, request);
|
||||||
|
|
||||||
status_t pre_status = callback->transact(intercept::kPreTransact, pre_req, &pre_resp);
|
if (callback->transact(intercept::kPreTransact, pre_req, &pre_resp) != OK) {
|
||||||
if (pre_status != OK) {
|
LOGW("[TX_ID: %" PRIu64 "] Pre-transaction callback failed. Forwarding original call.", tx_id);
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,11 @@ object App {
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
SystemLogger.info("Welcome to TEESimulator!")
|
SystemLogger.info("Welcome to TEESimulator!")
|
||||||
|
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
|
||||||
|
SystemLogger.error("Uncaught exception on ${thread.name}", throwable)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Initialize the Android framework environment
|
|
||||||
prepareEnvironment()
|
prepareEnvironment()
|
||||||
// Initialize and start the appropriate keystore interceptors.
|
// Initialize and start the appropriate keystore interceptors.
|
||||||
initializeInterceptors()
|
initializeInterceptors()
|
||||||
|
|||||||
@@ -109,17 +109,17 @@ abstract class BinderInterceptor : Binder() {
|
|||||||
* `handlePostTransact`).
|
* `handlePostTransact`).
|
||||||
*/
|
*/
|
||||||
final override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
|
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 txId = data.readLong()
|
||||||
val result =
|
val result = try {
|
||||||
when (code) {
|
when (code) {
|
||||||
// These codes are defined in the native layer to distinguish hook types.
|
|
||||||
PRE_TRANSACT_CODE -> handlePreTransact(txId, data)
|
PRE_TRANSACT_CODE -> handlePreTransact(txId, data)
|
||||||
POST_TRANSACT_CODE -> handlePostTransact(txId, data)
|
POST_TRANSACT_CODE -> handlePostTransact(txId, data)
|
||||||
else -> return super.onTransact(code, data, reply, flags)
|
else -> return super.onTransact(code, data, reply, flags)
|
||||||
}
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
// The reply parcel is guaranteed to be non-null for our custom transactions.
|
SystemLogger.error("[TX_ID: $txId] Interceptor exception, falling through to HAL", e)
|
||||||
|
TransactionResult.ContinueAndSkipPost
|
||||||
|
}
|
||||||
writeResultToReply(result, reply!!)
|
writeResultToReply(result, reply!!)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -289,6 +289,9 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
|
|||||||
callingPid,
|
callingPid,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!ConfigurationManager.shouldPatch(callingUid))
|
||||||
|
return TransactionResult.SkipTransaction
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
val response = reply.readTypedObject(KeyEntryResponse.CREATOR)!!
|
val response = reply.readTypedObject(KeyEntryResponse.CREATOR)!!
|
||||||
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
||||||
|
|||||||
+34
-14
@@ -82,7 +82,8 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
||||||
|
|
||||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
||||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||||
|
?: return TransactionResult.ContinueAndSkipPost
|
||||||
SystemLogger.info(
|
SystemLogger.info(
|
||||||
"[TX_ID: $txId] Forward to post-importKey hook for ${keyDescriptor.alias}[${keyDescriptor.nspace}]"
|
"[TX_ID: $txId] Forward to post-importKey hook for ${keyDescriptor.alias}[${keyDescriptor.nspace}]"
|
||||||
)
|
)
|
||||||
@@ -140,6 +141,10 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
metadata.authorizations =
|
metadata.authorizations =
|
||||||
InterceptorUtils.patchAuthorizations(metadata.authorizations, callingUid)
|
InterceptorUtils.patchAuthorizations(metadata.authorizations, callingUid)
|
||||||
patchedChains[keyId] = newChain
|
patchedChains[keyId] = newChain
|
||||||
|
teeResponses[keyId] = KeyEntryResponse().apply {
|
||||||
|
this.metadata = metadata
|
||||||
|
iSecurityLevel = original
|
||||||
|
}
|
||||||
SystemLogger.debug("Cached patched certificate chain for imported key $keyId.")
|
SystemLogger.debug("Cached patched certificate chain for imported key $keyId.")
|
||||||
return InterceptorUtils.createTypedObjectReply(metadata)
|
return InterceptorUtils.createTypedObjectReply(metadata)
|
||||||
}
|
}
|
||||||
@@ -148,8 +153,10 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
logTransaction(txId, "post-${transactionNames[code]!!}", callingUid, callingPid)
|
logTransaction(txId, "post-${transactionNames[code]!!}", callingUid, callingPid)
|
||||||
|
|
||||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
||||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||||
val params = data.createTypedArray(KeyParameter.CREATOR)!!
|
?: return TransactionResult.SkipTransaction
|
||||||
|
val params = data.createTypedArray(KeyParameter.CREATOR)
|
||||||
|
?: return TransactionResult.SkipTransaction
|
||||||
val parsedParams = KeyMintAttestation(params)
|
val parsedParams = KeyMintAttestation(params)
|
||||||
val forced = data.readBoolean()
|
val forced = data.readBoolean()
|
||||||
if (forced)
|
if (forced)
|
||||||
@@ -157,7 +164,8 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
"[TX_ID: $txId] Current operation has a very high pruning power."
|
"[TX_ID: $txId] Current operation has a very high pruning power."
|
||||||
)
|
)
|
||||||
val response: CreateOperationResponse =
|
val response: CreateOperationResponse =
|
||||||
reply.readTypedObject(CreateOperationResponse.CREATOR)!!
|
reply.readTypedObject(CreateOperationResponse.CREATOR)
|
||||||
|
?: return TransactionResult.SkipTransaction
|
||||||
SystemLogger.verbose(
|
SystemLogger.verbose(
|
||||||
"[TX_ID: $txId] CreateOperationResponse: ${response.iOperation} ${response.operationChallenge}"
|
"[TX_ID: $txId] CreateOperationResponse: ${response.iOperation} ${response.operationChallenge}"
|
||||||
)
|
)
|
||||||
@@ -190,9 +198,6 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
val metadata: KeyMetadata =
|
val metadata: KeyMetadata =
|
||||||
reply.readTypedObject(KeyMetadata.CREATOR)
|
reply.readTypedObject(KeyMetadata.CREATOR)
|
||||||
?: return TransactionResult.SkipTransaction
|
?: return TransactionResult.SkipTransaction
|
||||||
KeyMintAttestation(
|
|
||||||
metadata.authorizations?.map { it.keyParameter }?.toTypedArray() ?: emptyArray()
|
|
||||||
)
|
|
||||||
val originalChain =
|
val originalChain =
|
||||||
CertificateHelper.getCertificateChain(metadata)
|
CertificateHelper.getCertificateChain(metadata)
|
||||||
?: return TransactionResult.SkipTransaction
|
?: return TransactionResult.SkipTransaction
|
||||||
@@ -201,16 +206,23 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
|
|
||||||
// Cache the newly patched chain to ensure consistency across subsequent API calls.
|
// Cache the newly patched chain to ensure consistency across subsequent API calls.
|
||||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
||||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||||
val key = metadata.key!!
|
?: return TransactionResult.SkipTransaction
|
||||||
|
val key = metadata.key
|
||||||
|
?: return TransactionResult.SkipTransaction
|
||||||
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
||||||
CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow()
|
CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow()
|
||||||
metadata.authorizations =
|
metadata.authorizations =
|
||||||
InterceptorUtils.patchAuthorizations(metadata.authorizations, callingUid)
|
InterceptorUtils.patchAuthorizations(metadata.authorizations, callingUid)
|
||||||
|
|
||||||
// We must clean up cached generated keys before storing the patched chain
|
|
||||||
cleanupKeyData(keyId)
|
cleanupKeyData(keyId)
|
||||||
patchedChains[keyId] = newChain
|
patchedChains[keyId] = newChain
|
||||||
|
|
||||||
|
teeResponses[keyId] = KeyEntryResponse().apply {
|
||||||
|
this.metadata = metadata
|
||||||
|
iSecurityLevel = original
|
||||||
|
}
|
||||||
|
|
||||||
SystemLogger.debug(
|
SystemLogger.debug(
|
||||||
"Cached patched certificate chain for $keyId. (${key.alias} [${key.domain}, ${key.nspace}])"
|
"Cached patched certificate chain for $keyId. (${key.alias} [${key.domain}, ${key.nspace}])"
|
||||||
)
|
)
|
||||||
@@ -232,9 +244,9 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
data: Parcel,
|
data: Parcel,
|
||||||
): TransactionResult {
|
): TransactionResult {
|
||||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
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>? =
|
val resolvedEntry: Map.Entry<KeyIdentifier, GeneratedKeyInfo>? =
|
||||||
when (keyDescriptor.domain) {
|
when (keyDescriptor.domain) {
|
||||||
Domain.KEY_ID -> {
|
Domain.KEY_ID -> {
|
||||||
@@ -414,13 +426,15 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
private fun handleGenerateKey(txId: Long, callingUid: Int, callingPid: Int, data: Parcel): TransactionResult {
|
private fun handleGenerateKey(txId: Long, callingUid: Int, callingPid: Int, data: Parcel): TransactionResult {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
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)
|
val attestationKey = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||||
SystemLogger.debug(
|
SystemLogger.debug(
|
||||||
"Handling generateKey ${keyDescriptor.alias}, attestKey=${attestationKey?.alias}"
|
"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 parsedParams = KeyMintAttestation(params)
|
||||||
|
|
||||||
val challenge = parsedParams.attestationChallenge
|
val challenge = parsedParams.attestationChallenge
|
||||||
@@ -478,10 +492,16 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
|
|
||||||
val isAuto = ConfigurationManager.isAutoMode(callingUid)
|
val isAuto = ConfigurationManager.isAutoMode(callingUid)
|
||||||
|
|
||||||
|
val isStrongBox = securityLevel == SecurityLevel.STRONGBOX
|
||||||
|
|
||||||
when {
|
when {
|
||||||
forceGenerate -> doSoftwareGeneration(
|
forceGenerate -> doSoftwareGeneration(
|
||||||
callingUid, keyDescriptor, attestationKey, parsedParams, isAttestKeyRequest
|
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(
|
isAuto && !teeFunctional -> raceTeePatch(
|
||||||
callingUid, keyDescriptor, attestationKey, params, parsedParams, isAttestKeyRequest
|
callingUid, keyDescriptor, attestationKey, params, parsedParams, isAttestKeyRequest
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user