diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index afd1a94bf5069..61bc843aad795 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -16,7 +16,15 @@ package com.android.server.fingerprint; +import static android.Manifest.permission.USE_BIOMETRIC; +import static android.Manifest.permission.USE_FINGERPRINT; + +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricPromptReceiver; @@ -26,12 +34,16 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.EventLog; import android.util.Slog; +import com.android.internal.R; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; +import java.util.List; + /** * A class to keep track of the authentication state for a given client. */ @@ -156,10 +168,68 @@ public abstract class AuthenticationClient extends ClientMonitor { boolean result = false; boolean authenticated = fingerId != 0; + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !isKeyguard(getContext(), getOwnerString())) { + final ActivityManager activityManager = + (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); + final IActivityManager activityManagerService = activityManager != null + ? activityManager.getService() + : null; + if (activityManagerService == null) { + Slog.e(TAG, "Unable to get activity manager service"); + isBackgroundAuth = true; + } else { + try { + final List tasks = + activityManagerService.getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + // If the fingerprint dialog is showing, notify authentication succeeded if (mBundle != null) { try { if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Dialog notified"); + } + mStatusBarService.onFingerprintAuthenticated(); } else { mStatusBarService.onFingerprintHelp(getContext().getResources().getString( @@ -178,6 +248,14 @@ public abstract class AuthenticationClient extends ClientMonitor { if (!authenticated) { receiver.onAuthenticationFailed(getHalDeviceId()); } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Receiver notified"); + } + if (DEBUG) { Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString() + ", id=" + fingerId + ", gp=" + groupId + ")"); @@ -226,6 +304,13 @@ public abstract class AuthenticationClient extends ClientMonitor { } result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Lockout reset"); + } + if (receiver != null) { vibrateSuccess(); } @@ -236,6 +321,20 @@ public abstract class AuthenticationClient extends ClientMonitor { return result; } + private static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasFingerPermission = context.checkCallingOrSelfPermission(USE_FINGERPRINT) + == PackageManager.PERMISSION_GRANTED; + final boolean hasBiometricPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC) + == PackageManager.PERMISSION_GRANTED; + final boolean hasPermission = hasFingerPermission || hasBiometricPermission; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } + /** * Start authentication */