From 5df76eacd14faab704ce8b17ee6b658fa566d857 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. --- .gitignore | 6 ++ .../shim/KeyMintSecurityLevelInterceptor.kt | 16 ++++- .../util/AndroidPermissionUtils.kt | 72 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/matrix/TEESimulator/util/AndroidPermissionUtils.kt diff --git a/.gitignore b/.gitignore index 1fcb152..3f5d7ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ out +.gradle +.kotlin +app/build +build +native-certgen/target +app/src/main/jniLibs 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