fix(interception): absorb upstream correctness fixes and patch error reply format

Cherry-pick three upstream fixes: Parcel position reset in hasException()
so the method doesn't consume reply data (7804743), list_past_alias
enumeration filter inversion (2aac65c), and KeyMetadata alignment with
AOSP semantics — modificationTimeMs, Tag.ORIGIN, KeyDescriptor
normalization (86db5bf).

Additionally, createErrorReply() was missing the empty remote stack
trace header int between the exception message and error code, per
AOSP Status.cpp:196. Binder readers expecting the standard
EX_SERVICE_SPECIFIC wire format would misparse our error replies.
This commit is contained in:
Enginex0
2026-03-16 13:23:36 +01:00
parent d21822eb9d
commit 8001a8678a
3 changed files with 21 additions and 3 deletions
@@ -18,6 +18,7 @@ object InterceptorUtils {
val parcel = Parcel.obtain().apply {
writeInt(EX_SERVICE_SPECIFIC)
writeString(null)
writeInt(0) // empty remote stack trace header (AOSP Status.cpp:196)
writeInt(errorCode)
}
return BinderInterceptor.TransactionResult.OverrideReply(parcel)
@@ -119,6 +120,8 @@ object InterceptorUtils {
/** Checks if a reply parcel contains an exception without consuming it. */
fun hasException(reply: Parcel): Boolean {
return runCatching { reply.readException() }.exceptionOrNull() != null
val exception = runCatching { reply.readException() }.exceptionOrNull()
if (exception != null) reply.setDataPosition(0)
return exception != null
}
}
@@ -129,7 +129,7 @@ object ListEntriesHandler {
startPastAlias: String?,
): List<KeyDescriptor> {
return KeyMintSecurityLevelInterceptor.generatedKeys.keys
.filter { it.uid == uid && (startPastAlias == null || it.alias < startPastAlias) }
.filter { it.uid == uid && (startPastAlias == null || it.alias > startPastAlias) }
.map { keyId ->
KeyDescriptor().apply {
this.domain = Domain.APP
@@ -3,6 +3,7 @@ package org.matrix.TEESimulator.interception.keystore.shim
import android.hardware.security.keymint.Algorithm
import android.hardware.security.keymint.KeyParameter
import android.hardware.security.keymint.KeyParameterValue
import android.hardware.security.keymint.KeyOrigin
import android.hardware.security.keymint.Tag
import android.os.IBinder
import android.os.Parcel
@@ -425,12 +426,20 @@ class KeyMintSecurityLevelInterceptor(
params: KeyMintAttestation,
descriptor: KeyDescriptor,
): KeyEntryResponse {
val normalizedKeyDescriptor =
KeyDescriptor().apply {
domain = Domain.KEY_ID
nspace = descriptor.nspace
alias = null
blob = null
}
val metadata =
KeyMetadata().apply {
keySecurityLevel = securityLevel
key = descriptor
key = normalizedKeyDescriptor
CertificateHelper.updateCertificateChain(this, chain.toTypedArray()).getOrThrow()
authorizations = params.toAuthorizations(securityLevel)
modificationTimeMs = System.currentTimeMillis()
}
return KeyEntryResponse().apply {
this.metadata = metadata
@@ -665,6 +674,12 @@ private fun KeyMintAttestation.toAuthorizations(securityLevel: Int): Array<Autho
authList.add(createAuth(Tag.ALGORITHM, KeyParameterValue.algorithm(this.algorithm)))
authList.add(createAuth(Tag.KEY_SIZE, KeyParameterValue.integer(this.keySize)))
authList.add(createAuth(Tag.EC_CURVE, KeyParameterValue.ecCurve(this.ecCurve)))
authList.add(
createAuth(
Tag.ORIGIN,
KeyParameterValue.origin(this.origin ?: KeyOrigin.GENERATED),
)
)
authList.add(createAuth(Tag.NO_AUTH_REQUIRED, KeyParameterValue.boolValue(true)))
return authList.toTypedArray()