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

Commit 3eab2c0d authored by Rhed Jao's avatar Rhed Jao Committed by Android (Google) Code Review
Browse files

Merge "Enforce package visibility filtering on AccountManager APIs"

parents 74047258 c1ebe670
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -1029,7 +1029,9 @@ public class AccountManager {
     * @param password The password to associate with the account, null for none
     * @param extras String values to use for the account's userdata, null for none
     * @param visibility Map from packageName to visibility values which will be set before account
     *        is added. See {@link #getAccountVisibility} for possible values.
     *        is added. See {@link #getAccountVisibility} for possible values. Declaring
     *        <a href="/training/basics/intents/package-visibility">package visibility</a> needs for
     *        package names in the map is needed, if the caller is targeting API level 34 and above.
     *
     * @return True if the account was successfully added, false if the account already exists, the
     *         account is null, or another error occurs.
@@ -1113,7 +1115,9 @@ public class AccountManager {
     * the specified account.
     *
     * @param account {@link Account} to update visibility
     * @param packageName Package name of the application to modify account visibility
     * @param packageName Package name of the application to modify account visibility. Declaring
     *        <a href="/training/basics/intents/package-visibility">package visibility</a> needs
     *        for it is needed, if the caller is targeting API level 34 and above.
     * @param visibility New visibility value
     *
     * @return True, if visibility value was successfully updated.
@@ -1145,7 +1149,9 @@ public class AccountManager {
     * @param account {@link Account} to get visibility
     * @param packageName Package name of the application to get account visibility
     *
     * @return int Visibility of given account.
     * @return int Visibility of given account. For the caller targeting API level 34 and above,
     * {@link #VISIBILITY_NOT_VISIBLE} is returned if the given package is filtered by the rules of
     * <a href="/training/basics/intents/package-visibility">package visibility</a>.
     */
    public @AccountVisibility int getAccountVisibility(Account account, String packageName) {
        if (account == null)
+50 −22
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@ import android.app.PendingIntent;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ComponentName;
@@ -70,6 +73,7 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteFullException;
import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -196,6 +200,14 @@ public class AccountManagerService
    private static final int SIGNATURE_CHECK_MATCH = 1;
    private static final int SIGNATURE_CHECK_UID_MATCH = 2;

    /**
     * Apps targeting Android U and above need to declare the package visibility needs in the
     * manifest to access the AccountManager APIs.
     */
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    private static final long ENFORCE_PACKAGE_VISIBILITY_FILTERING = 154726397;

    static {
        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
@@ -527,7 +539,7 @@ public class AccountManagerService
     */
    private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
            List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
        if (!packageExistsForUser(packageName, accounts.userId)) {
        if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) {
            Log.w(TAG, "getAccountsAndVisibilityForPackage#Package not found " + packageName);
            return new LinkedHashMap<>();
        }
@@ -629,6 +641,9 @@ public class AccountManagerService
                   return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
                }
            }
            if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) {
                return AccountManager.VISIBILITY_NOT_VISIBLE;
            }
            return resolveAccountVisibility(account, packageName, accounts);
        } finally {
            restoreCallingIdentity(identityToken);
@@ -779,7 +794,7 @@ public class AccountManagerService
        try {
            UserAccounts accounts = getUserAccounts(userId);
            return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
                accounts);
                    accounts, callingUid);
        } finally {
            restoreCallingIdentity(identityToken);
        }
@@ -798,11 +813,12 @@ public class AccountManagerService
     * @param newVisibility New visibility calue
     * @param notify if the flag is set applications will get notification about visibility change
     * @param accounts UserAccount that currently hosts the account and application
     * @param callingUid The caller's uid.
     *
     * @return True if account visibility was changed.
     */
    private boolean setAccountVisibility(Account account, String packageName, int newVisibility,
            boolean notify, UserAccounts accounts) {
            boolean notify, UserAccounts accounts, int callingUid) {
        synchronized (accounts.dbLock) {
            synchronized (accounts.cacheLock) {
                Map<String, Integer> packagesToVisibility;
@@ -813,8 +829,8 @@ public class AccountManagerService
                                getRequestingPackages(account, accounts);
                        accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
                    } else {
                        if (!packageExistsForUser(packageName, accounts.userId)) {
                            return false; // package is not installed.
                        if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) {
                            return false; // package is not installed or not visible.
                        }
                        packagesToVisibility = new HashMap<>();
                        packagesToVisibility.put(packageName,
@@ -826,8 +842,8 @@ public class AccountManagerService
                    }
                } else {
                    // Notifications will not be send - only used during add account.
                    if (!isSpecialPackageKey(packageName) &&
                            !packageExistsForUser(packageName, accounts.userId)) {
                    if (!isSpecialPackageKey(packageName)
                            && !canCallerAccessPackage(packageName, callingUid, accounts.userId)) {
                        // package is not installed and not meta value.
                        return false;
                    }
@@ -1045,20 +1061,6 @@ public class AccountManagerService
        return (receivers != null && receivers.size() > 0);
    }

    private boolean packageExistsForUser(String packageName, int userId) {
        try {
            final long identityToken = clearCallingIdentity();
            try {
                mPackageManager.getPackageUidAsUser(packageName, userId);
                return true;
            } finally {
                restoreCallingIdentity(identityToken);
            }
        } catch (NameNotFoundException e) {
            return false;
        }
    }

    /**
     * Returns true if packageName is one of special values.
     */
@@ -1903,7 +1905,7 @@ public class AccountManagerService
                        for (Entry<String, Integer> entry : packageToVisibility.entrySet()) {
                            setAccountVisibility(account, entry.getKey() /* package */,
                                    entry.getValue() /* visibility */, false /* notify */,
                                    accounts);
                                    accounts, callingUid);
                        }
                    }
                    accounts.accountsDb.setTransactionSuccessful();
@@ -5915,6 +5917,32 @@ public class AccountManagerService
        return (dpmi != null) && (dpmi.isActiveProfileOwner(uid) || dpmi.isActiveDeviceOwner(uid));
    }

    /**
     * Filter the access to the target package by rules of the package visibility if the caller
     * targeting API level U and above. Otherwise, returns true if the package is installed on
     * the device.
     *
     * @param targetPkgName The package name to check.
     * @param callingUid The caller that is going to access the package.
     * @param userId The user ID where the target package resides.
     * @return true if the caller is able to access the package.
     */
    private boolean canCallerAccessPackage(@NonNull String targetPkgName, int callingUid,
            int userId) {
        final PackageManagerInternal pmInternal =
                LocalServices.getService(PackageManagerInternal.class);
        if (!CompatChanges.isChangeEnabled(ENFORCE_PACKAGE_VISIBILITY_FILTERING, callingUid)) {
            return pmInternal.getPackageUid(
                    targetPkgName, 0 /* flags */, userId) != Process.INVALID_UID;
        }
        final boolean canAccess = !pmInternal.filterAppAccess(targetPkgName, callingUid, userId);
        if (!canAccess && Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Package " + targetPkgName + " is not visible to caller " + callingUid
                    + " for user " + userId);
        }
        return canAccess;
    }

    @Override
    public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
            throws RemoteException {