Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cf71d71 authored by Curtis Belmonte's avatar Curtis Belmonte Committed by Android (Google) Code Review
Browse files

Merge changes from topic "bio_service_restrict"

* changes:
  Make BiometricService check for internal permission
  Configure BiometricPrompt to use AuthService.
parents 780d2bb7 a8b50a6f
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -387,7 +387,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan

    private final IBinder mToken = new Binder();
    private final Context mContext;
    private final IBiometricService mService;
    private final IAuthService mService;
    private final Bundle mBundle;
    private final ButtonInfo mPositiveButtonInfo;
    private final ButtonInfo mNegativeButtonInfo;
@@ -465,8 +465,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        mBundle = bundle;
        mPositiveButtonInfo = positiveButtonInfo;
        mNegativeButtonInfo = negativeButtonInfo;
        mService = IBiometricService.Stub.asInterface(
                ServiceManager.getService(Context.BIOMETRIC_SERVICE));
        mService = IAuthService.Stub.asInterface(
                ServiceManager.getService(Context.AUTH_SERVICE));
    }

    /**
+3 −0
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ interface IAuthService {
    void authenticate(IBinder token, long sessionId, int userId,
            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);

    // Cancel authentication for the given sessionId
    void cancelAuthentication(IBinder token, String opPackageName);

    // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
    // Checks if biometrics can be used.
    int canAuthenticate(String opPackageName, int userId, int authenticators);
+8 −5
Original line number Diff line number Diff line
@@ -29,13 +29,15 @@ interface IBiometricService {
    // Requests authentication. The service choose the appropriate biometric to use, and show
    // the corresponding BiometricDialog.
    void authenticate(IBinder token, long sessionId, int userId,
            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);
            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle,
            int callingUid, int callingPid, int callingUserId);

    // Cancel authentication for the given sessionId
    void cancelAuthentication(IBinder token, String opPackageName);
    // Cancel authentication for the given session.
    void cancelAuthentication(IBinder token, String opPackageName, int callingUid, int callingPid,
            int callingUserId);

    // Checks if biometrics can be used.
    int canAuthenticate(String opPackageName, int userId, int authenticators);
    int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);

    // Checks if any biometrics are enrolled.
    boolean hasEnrolledBiometrics(int userId, String opPackageName);
@@ -47,7 +49,8 @@ interface IBiometricService {
            IBiometricAuthenticator authenticator);

    // Register callback for when keyguard biometric eligibility changes.
    void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
    void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback,
            int callingUserId);

    // Explicitly set the active user.
    void setActiveUser(int userId);
+95 −31
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static android.hardware.biometrics.BiometricManager.Authenticators;

import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IAuthService;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -38,6 +39,7 @@ import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.face.IFaceService;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.iris.IIrisService;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -133,14 +135,12 @@ public class AuthService extends SystemService {
        public void authenticate(IBinder token, long sessionId, int userId,
                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle)
                throws RemoteException {
            final int callingUserId = UserHandle.getCallingUserId();

            // In the BiometricServiceBase, do the AppOps and foreground check.
            // Only allow internal clients to authenticate with a different userId.
            final int callingUserId = UserHandle.getCallingUserId();
            if (userId == callingUserId) {
                // Check the USE_BIOMETRIC permission here.
                checkPermission();
            } else {
                // Only allow internal clients to authenticate with a different userId
                Slog.w(TAG, "User " + callingUserId + " is requesting authentication of userid: "
                        + userId);
                checkInternalPermission();
@@ -151,13 +151,51 @@ public class AuthService extends SystemService {
                return;
            }

            mBiometricService.authenticate(token, sessionId, userId, receiver, opPackageName,
                    bundle);
            // Only allow internal clients to enable non-public options.
            if (bundle.getBoolean(BiometricPrompt.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS)
                    || bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false)) {
                checkInternalPermission();
            }

            final int callingUid = Binder.getCallingUid();
            final int callingPid = Binder.getCallingPid();
            final long identity = Binder.clearCallingIdentity();
            try {
                mBiometricService.authenticate(
                        token, sessionId, userId, receiver, opPackageName, bundle, callingUid,
                        callingPid, callingUserId);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public void cancelAuthentication(IBinder token, String opPackageName)
                throws RemoteException {
            checkPermission();

            if (token == null || opPackageName == null) {
                Slog.e(TAG, "Unable to authenticate, one or more null arguments");
                return;
            }

            final int callingUid = Binder.getCallingUid();
            final int callingPid = Binder.getCallingPid();
            final int callingUserId = UserHandle.getCallingUserId();
            final long identity = Binder.clearCallingIdentity();
            try {
                mBiometricService.cancelAuthentication(token, opPackageName, callingUid,
                        callingPid, callingUserId);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public int canAuthenticate(String opPackageName, int userId,
                @Authenticators.Types int authenticators) throws RemoteException {

            // Only allow internal clients to call canAuthenticate with a different userId.
            final int callingUserId = UserHandle.getCallingUserId();
            Slog.d(TAG, "canAuthenticate, userId: " + userId + ", callingUserId: " + callingUserId
                    + ", authenticators: " + authenticators);
@@ -166,33 +204,61 @@ public class AuthService extends SystemService {
            } else {
                checkPermission();
            }
            return mBiometricService.canAuthenticate(opPackageName, userId, authenticators);

            final long identity = Binder.clearCallingIdentity();
            try {
                return mBiometricService.canAuthenticate(
                        opPackageName, userId, callingUserId, authenticators);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public boolean hasEnrolledBiometrics(int userId, String opPackageName)
                throws RemoteException {
            checkInternalPermission();
            final long identity = Binder.clearCallingIdentity();
            try {
                return mBiometricService.hasEnrolledBiometrics(userId, opPackageName);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
                throws RemoteException {
        public void registerEnabledOnKeyguardCallback(
                IBiometricEnabledOnKeyguardCallback callback) throws RemoteException {
            checkInternalPermission();
            mBiometricService.registerEnabledOnKeyguardCallback(callback);
            final int callingUserId = UserHandle.getCallingUserId();
            final long identity = Binder.clearCallingIdentity();
            try {
                mBiometricService.registerEnabledOnKeyguardCallback(callback, callingUserId);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public void setActiveUser(int userId) throws RemoteException {
            checkInternalPermission();
            final long identity = Binder.clearCallingIdentity();
            try {
                mBiometricService.setActiveUser(userId);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public void resetLockout(byte[] token) throws RemoteException {
            checkInternalPermission();
            final long identity = Binder.clearCallingIdentity();
            try {
                mBiometricService.resetLockout(token);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

@@ -207,8 +273,23 @@ public class AuthService extends SystemService {
        mImpl = new AuthServiceImpl();
    }

    private void registerAuthenticator(SensorConfig config) throws RemoteException {
    @Override
    public void onStart() {
        mBiometricService = mInjector.getBiometricService();

        final String[] configs = mInjector.getConfiguration(getContext());
        for (String config : configs) {
            try {
                registerAuthenticator(new SensorConfig(config));
            } catch (RemoteException e) {
                Slog.e(TAG, "Remote exception", e);
            }
        }

        mInjector.publishBinderService(this, mImpl);
    }

    private void registerAuthenticator(SensorConfig config) throws RemoteException {
        Slog.d(TAG, "Registering ID: " + config.mId
                + " Modality: " + config.mModality
                + " Strength: " + config.mStrength);
@@ -258,23 +339,6 @@ public class AuthService extends SystemService {
                authenticator);
    }

    @Override
    public void onStart() {
        mBiometricService = mInjector.getBiometricService();

        final String[] configs = mInjector.getConfiguration(getContext());

        for (int i = 0; i < configs.length; i++) {
            try {
                registerAuthenticator(new SensorConfig(configs[i]));
            } catch (RemoteException e) {
                Slog.e(TAG, "Remote exception", e);
            }

        }

        mInjector.publishBinderService(this, mImpl);
    }

    private void checkInternalPermission() {
        getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
+43 −79
Original line number Diff line number Diff line
@@ -16,9 +16,7 @@

package com.android.server.biometrics;

import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
@@ -33,7 +31,6 @@ import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
@@ -338,7 +335,10 @@ public class BiometricService extends SystemService {
                    SomeArgs args = (SomeArgs) msg.obj;
                    handleCancelAuthentication(
                            (IBinder) args.arg1 /* token */,
                            (String) args.arg2 /* opPackageName */);
                            (String) args.arg2 /* opPackageName */,
                            args.argi1 /* callingUid */,
                            args.argi2 /* callingPid */,
                            args.argi3 /* callingUserId */);
                    args.recycle();
                    break;
                }
@@ -567,8 +567,7 @@ public class BiometricService extends SystemService {
    final IBiometricServiceReceiverInternal mInternalReceiver =
            new IBiometricServiceReceiverInternal.Stub() {
        @Override
        public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
                throws RemoteException {
        public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = requireConfirmation;
            args.arg2 = token;
@@ -576,8 +575,7 @@ public class BiometricService extends SystemService {
        }

        @Override
        public void onAuthenticationFailed()
                throws RemoteException {
        public void onAuthenticationFailed() {
            Slog.v(TAG, "onAuthenticationFailed");
            mHandler.obtainMessage(MSG_ON_AUTHENTICATION_REJECTED).sendToTarget();
        }
@@ -648,22 +646,9 @@ public class BiometricService extends SystemService {

        @Override // Binder call
        public void authenticate(IBinder token, long sessionId, int userId,
                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle)
                throws RemoteException {
            final int callingUid = Binder.getCallingUid();
            final int callingPid = Binder.getCallingPid();
            final int callingUserId = UserHandle.getCallingUserId();

            // In the BiometricServiceBase, check do the AppOps and foreground check.
            if (userId == callingUserId) {
                // Check the USE_BIOMETRIC permission here.
                checkPermission();
            } else {
                // Only allow internal clients to authenticate with a different userId
                Slog.w(TAG, "User " + callingUserId + " is requesting authentication of userid: "
                        + userId);
                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
                int callingUid, int callingPid, int callingUserId) {
            checkInternalPermission();
            }

            if (token == null || receiver == null || opPackageName == null || bundle == null) {
                Slog.e(TAG, "Unable to authenticate, one or more null arguments");
@@ -674,19 +659,10 @@ public class BiometricService extends SystemService {
                throw new SecurityException("Invalid authenticator configuration");
            }

            if (bundle.getBoolean(BiometricPrompt.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS)) {
                checkInternalPermission();
            }

            Utils.combineAuthenticatorBundles(bundle);

            // Check the usage of this in system server. Need to remove this check if it becomes a
            // public API.
            final boolean useDefaultTitle =
                    bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false);
            if (useDefaultTitle) {
                checkInternalPermission();
                // Set the default title if necessary
            // Set the default title if necessary.
            if (bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false)) {
                if (TextUtils.isEmpty(bundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
                    bundle.putCharSequence(BiometricPrompt.KEY_TITLE,
                            getContext().getString(R.string.biometric_dialog_default_title));
@@ -708,29 +684,28 @@ public class BiometricService extends SystemService {
        }

        @Override // Binder call
        public void cancelAuthentication(IBinder token, String opPackageName)
                throws RemoteException {
            checkPermission();
        public void cancelAuthentication(IBinder token, String opPackageName,
                int callingUid, int callingPid, int callingUserId) {
            checkInternalPermission();

            SomeArgs args = SomeArgs.obtain();
            args.arg1 = token;
            args.arg2 = opPackageName;
            args.argi1 = callingUid;
            args.argi2 = callingPid;
            args.argi3 = callingUserId;
            mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget();
        }

        @Override // Binder call
        public int canAuthenticate(String opPackageName, int userId,
        public int canAuthenticate(String opPackageName, int userId, int callingUserId,
                @Authenticators.Types int authenticators) {
            checkInternalPermission();

            Slog.d(TAG, "canAuthenticate: User=" + userId
                    + ", Caller=" + UserHandle.getCallingUserId()
                    + ", Caller=" + callingUserId
                    + ", Authenticators=" + authenticators);

            if (userId != UserHandle.getCallingUserId()) {
                checkInternalPermission();
            } else {
                checkPermission();
            }

            if (!Utils.isValidAuthenticatorConfig(authenticators)) {
                throw new SecurityException("Invalid authenticator configuration");
            }
@@ -739,14 +714,11 @@ public class BiometricService extends SystemService {
            bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);

            int biometricConstantsResult = BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
            final long ident = Binder.clearCallingIdentity();
            try {
                biometricConstantsResult = checkAndGetAuthenticators(userId, bundle, opPackageName,
                        false /* checkDevicePolicyManager */).second;
            } catch (RemoteException e) {
                Slog.e(TAG, "Remote exception", e);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }

            return Utils.biometricConstantsToBiometricManager(biometricConstantsResult);
@@ -756,7 +728,6 @@ public class BiometricService extends SystemService {
        public boolean hasEnrolledBiometrics(int userId, String opPackageName) {
            checkInternalPermission();

            final long ident = Binder.clearCallingIdentity();
            try {
                for (AuthenticatorWrapper authenticator : mAuthenticators) {
                    if (authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) {
@@ -765,9 +736,8 @@ public class BiometricService extends SystemService {
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Remote exception", e);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }

            return false;
        }

@@ -815,14 +785,14 @@ public class BiometricService extends SystemService {
        }

        @Override // Binder call
        public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
                throws RemoteException {
        public void registerEnabledOnKeyguardCallback(
                IBiometricEnabledOnKeyguardCallback callback, int callingUserId) {
            checkInternalPermission();

            mEnabledOnKeyguardCallbacks.add(new EnabledOnKeyguardCallback(callback));
            try {
                callback.onChanged(BiometricSourceType.FACE,
                        mSettingObserver.getFaceEnabledOnKeyguard(),
                        UserHandle.getCallingUserId());
                        mSettingObserver.getFaceEnabledOnKeyguard(), callingUserId);
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception", e);
            }
@@ -831,30 +801,26 @@ public class BiometricService extends SystemService {
        @Override // Binder call
        public void setActiveUser(int userId) {
            checkInternalPermission();
            final long ident = Binder.clearCallingIdentity();

            try {
                for (AuthenticatorWrapper authenticator : mAuthenticators) {
                    authenticator.impl.setActiveUser(userId);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Remote exception", e);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        @Override // Binder call
        public void resetLockout(byte[] token) {
            checkInternalPermission();
            final long ident = Binder.clearCallingIdentity();

            try {
                for (AuthenticatorWrapper authenticator : mAuthenticators) {
                    authenticator.impl.resetLockout(token);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Remote exception", e);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
@@ -864,14 +830,6 @@ public class BiometricService extends SystemService {
                "Must have USE_BIOMETRIC_INTERNAL permission");
    }

    private void checkPermission() {
        if (getContext().checkCallingOrSelfPermission(USE_FINGERPRINT)
                != PackageManager.PERMISSION_GRANTED) {
            getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC,
                    "Must have USE_BIOMETRIC permission");
        }
    }

    /**
     * Class for injecting dependencies into BiometricService.
     * TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
@@ -1494,7 +1452,9 @@ public class BiometricService extends SystemService {
                    mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
                    // Cancel authentication. Skip the token/package check since we are cancelling
                    // from system server. The interface is permission protected so this is fine.
                    cancelInternal(null /* token */, null /* package */, false /* fromClient */);
                    cancelInternal(null /* token */, null /* package */,
                            mCurrentAuthSession.mCallingUid, mCurrentAuthSession.mCallingPid,
                            mCurrentAuthSession.mCallingUserId, false /* fromClient */);
                    break;

                case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
@@ -1505,7 +1465,9 @@ public class BiometricService extends SystemService {
                    );
                    // Cancel authentication. Skip the token/package check since we are cancelling
                    // from system server. The interface is permission protected so this is fine.
                    cancelInternal(null /* token */, null /* package */, false /* fromClient */);
                    cancelInternal(null /* token */, null /* package */, Binder.getCallingUid(),
                            Binder.getCallingPid(), UserHandle.getCallingUserId(),
                            false /* fromClient */);
                    break;

                case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED:
@@ -1555,7 +1517,9 @@ public class BiometricService extends SystemService {

        // Cancel authentication. Skip the token/package check since we are cancelling
        // from system server. The interface is permission protected so this is fine.
        cancelInternal(null /* token */, null /* package */, false /* fromClient */);
        cancelInternal(null /* token */, null /* package */, Binder.getCallingUid(),
                Binder.getCallingPid(), UserHandle.getCallingUserId(),
                false /* fromClient */);

        mCurrentAuthSession.mState = STATE_SHOWING_DEVICE_CREDENTIAL;
    }
@@ -1725,7 +1689,8 @@ public class BiometricService extends SystemService {
        }
    }

    private void handleCancelAuthentication(IBinder token, String opPackageName) {
    private void handleCancelAuthentication(IBinder token, String opPackageName, int callingUid,
            int callingPid, int callingUserId) {
        if (token == null || opPackageName == null) {
            Slog.e(TAG, "Unable to cancel, one or more null arguments");
            return;
@@ -1748,14 +1713,13 @@ public class BiometricService extends SystemService {
                Slog.e(TAG, "Remote exception", e);
            }
        } else {
            cancelInternal(token, opPackageName, true /* fromClient */);
            cancelInternal(token, opPackageName, callingUid, callingPid, callingUserId,
                    true /* fromClient */);
        }
    }

    void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        final int callingUserId = UserHandle.getCallingUserId();
    void cancelInternal(IBinder token, String opPackageName, int callingUid, int callingPid,
            int callingUserId, boolean fromClient) {

        if (mCurrentAuthSession == null) {
            Slog.w(TAG, "Skipping cancelInternal");
Loading