From 5defc0d832cdacf55e98b16aab192e56119be8e3 Mon Sep 17 00:00:00 2001 From: fatalcoder524 <11532648+fatalcoder524@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:49:54 +0000 Subject: [PATCH] fix(interception): Add permission checks for KeyMintSecurityLevelInterceptor and fix some regression 1. Add permission checks for KeyMintSecurityLevelInterceptor to ensure that only authorized users can access sensitive information about the security level of the key mint. 2. Fix regression where device id attestation was allowed for all users by adding appropriate permission checks. 3. Update .gitignore to exclude build artifacts and generated files to keep the repository clean and prevent accidental commits of unnecessary files. --- .../shim/KeyMintSecurityLevelInterceptor.kt | 16 ++++- .../util/AndroidPermissionUtils.kt | 72 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/matrix/TEESimulator/util/AndroidPermissionUtils.kt 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 010bc2d..176a7da 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 @@ -33,6 +33,7 @@ import org.matrix.TEESimulator.pki.CertificateHelper import org.matrix.TEESimulator.pki.KeyBoxManager import org.matrix.TEESimulator.pki.NativeCertGen import org.matrix.TEESimulator.util.AndroidDeviceUtils +import org.matrix.TEESimulator.util.AndroidPermissionUtils class KeyMintSecurityLevelInterceptor( private val original: IKeystoreSecurityLevel, @@ -267,11 +268,24 @@ class KeyMintSecurityLevelInterceptor( return InterceptorUtils.createErrorReply(RESPONSE_INVALID_ARGUMENT) } - if (params.any { it.tag == Tag.DEVICE_UNIQUE_ATTESTATION }) { + if (params.any { it.tag == Tag.DEVICE_UNIQUE_ATTESTATION } && !AndroidPermissionUtils.hasUniqueIdAttestationPermission(callingUid)) { SystemLogger.warning("[TX_ID: $txId] Rejecting DEVICE_UNIQUE_ATTESTATION for uid=$callingUid") return InterceptorUtils.createErrorReply(KEYMINT_CANNOT_ATTEST_IDS) } + val hasDeviceIdAttestation = params.any { + it.tag == Tag.ATTESTATION_ID_IMEI || + it.tag == Tag.ATTESTATION_ID_MEID || + it.tag == Tag.ATTESTATION_ID_SERIAL || + it.tag == Tag.DEVICE_UNIQUE_ATTESTATION || + it.tag == Tag.ATTESTATION_ID_SECOND_IMEI + } + + if(hasDeviceIdAttestation && !AndroidPermissionUtils.hasDeviceAttestationPermission(callingUid)) { + SystemLogger.warning("[TX_ID: $txId] Rejecting DEVICE_ID_ATTESTATION for uid=$callingUid") + return InterceptorUtils.createErrorReply(KEYMINT_CANNOT_ATTEST_IDS) + } + val keyId = KeyIdentifier(callingUid, keyDescriptor.alias) val isAttestKeyRequest = parsedParams.isAttestKey() diff --git a/app/src/main/java/org/matrix/TEESimulator/util/AndroidPermissionUtils.kt b/app/src/main/java/org/matrix/TEESimulator/util/AndroidPermissionUtils.kt new file mode 100644 index 0000000..d5877f3 --- /dev/null +++ b/app/src/main/java/org/matrix/TEESimulator/util/AndroidPermissionUtils.kt @@ -0,0 +1,72 @@ +package org.matrix.TEESimulator.util + +import android.annotation.SuppressLint +import android.content.Context +import android.content.pm.PackageManager +import org.matrix.TEESimulator.logging.SystemLogger + +object AndroidPermissionUtils { + + @SuppressLint("PrivateApi", "DiscouragedPrivateApi") + private fun getGlobalContext(): Context? { + return try { + // 1. Get the hidden ActivityThread class via reflection + val activityThreadClass = Class.forName("android.app.ActivityThread") + + // 2. Invoke the static currentActivityThread() method + val currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread") + currentActivityThreadMethod.isAccessible = true + val activityThread = currentActivityThreadMethod.invoke(null) + + if (activityThread == null) { + SystemLogger.warning("Reflection: ActivityThread.currentActivityThread() returned null") + return null + } + + // 3. Try to get the application context + val getApplicationMethod = activityThreadClass.getDeclaredMethod("getApplication") + getApplicationMethod.isAccessible = true + val application = getApplicationMethod.invoke(activityThread) as? Context + + if (application != null) return application + + // 4. Fallback to getSystemContext() if application is null (often happens in system_server) + val getSystemContextMethod = activityThreadClass.getDeclaredMethod("getSystemContext") + getSystemContextMethod.isAccessible = true + getSystemContextMethod.invoke(activityThread) as? Context + + } catch (e: Exception) { + SystemLogger.error("Reflection failed to get global context for permission check", e) + null + } + } + + /** + * Core permission check. + */ + fun hasPermission(uid: Int, permission: String): Boolean { + val context = getGlobalContext() ?: run { + SystemLogger.warning("AndroidPermissionUtils: Context is null, failing permission check safely.") + return false + } + + val result = context.checkPermission(permission, -1, uid) + return result == PackageManager.PERMISSION_GRANTED + } + + fun hasDeviceAttestationPermission(uid: Int): Boolean { + return hasPermission(uid, "android.permission.READ_PRIVILEGED_PHONE_STATE") + } + + fun hasUniqueIdAttestationPermission(uid: Int): Boolean { + return hasPermission(uid, "android.permission.REQUEST_UNIQUE_ID_ATTESTATION") + } + + fun hasManageUsersPermission(uid: Int): Boolean { + return hasPermission(uid, "android.permission.MANAGE_USERS") + } + + fun hasDumpPermission(uid: Int): Boolean { + return hasPermission(uid, "android.permission.DUMP") + } +} \ No newline at end of file