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

Commit 52fc221c authored by Hai Zhang's avatar Hai Zhang Committed by Android (Google) Code Review
Browse files

Merge "Move enforceCrossUser*Permission() back into PackageManagerService."

parents 7e2a4e8c 888c718b
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -517,7 +517,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
            String installerAttributionTag, int userId)
            throws IOException {
        final int callingUid = Binder.getCallingUid();
        mPermissionManager.enforceCrossUserPermission(
        mPm.enforceCrossUserPermission(
                callingUid, userId, true, true, "createSession");

        if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
@@ -912,7 +912,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
    @Override
    public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
        final int callingUid = Binder.getCallingUid();
        mPermissionManager.enforceCrossUserPermission(
        mPm.enforceCrossUserPermission(
                callingUid, userId, true, false, "getAllSessions");

        final List<SessionInfo> result = new ArrayList<>();
@@ -930,7 +930,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements

    @Override
    public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
        mPermissionManager.enforceCrossUserPermission(
        mPm.enforceCrossUserPermission(
                Binder.getCallingUid(), userId, true, false, "getMySessions");
        mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);

@@ -954,7 +954,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
    public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
                IntentSender statusReceiver, int userId) {
        final int callingUid = Binder.getCallingUid();
        mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
            mAppOps.checkPackage(callingUid, callerPackageName);
        }
@@ -1006,7 +1006,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
            String callerPackageName, IntentSender statusReceiver, int userId) {
        final int callingUid = Binder.getCallingUid();
        mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
        mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
            mAppOps.checkPackage(callingUid, callerPackageName);
        }
@@ -1037,7 +1037,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements

    @Override
    public void registerCallback(IPackageInstallerCallback callback, int userId) {
        mPermissionManager.enforceCrossUserPermission(
        mPm.enforceCrossUserPermission(
                Binder.getCallingUid(), userId, true, false, "registerCallback");
        registerCallback(callback, eventUserId -> userId == eventUserId);
    }
+245 −102

File changed.

Preview size limit exceeded, changes collapsed.

+28 −122
Original line number Diff line number Diff line
@@ -77,7 +77,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -96,6 +95,7 @@ import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
import android.os.Debug;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -754,7 +754,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        enforceCrossUserPermission(callingUid, userId,
                true,  // requireFullPermission
                false, // checkShell
                false, // requirePermissionWhenSameUser
                "getPermissionFlags");

        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -841,7 +840,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        enforceCrossUserPermission(callingUid, userId,
                true,  // requireFullPermission
                true,  // checkShell
                false, // requirePermissionWhenSameUser
                "updatePermissionFlags");

        if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0 && !overridePolicy) {
@@ -951,7 +949,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        enforceCrossUserPermission(callingUid, userId,
                true,  // requireFullPermission
                true,  // checkShell
                false, // requirePermissionWhenSameUser
                "updatePermissionFlagsForAllApps");

        // Only the system can change system fixed flags.
@@ -1555,7 +1552,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        enforceCrossUserPermission(callingUid, userId,
                true,  // requireFullPermission
                true,  // checkShell
                false, // requirePermissionWhenSameUser
                "grantRuntimePermission");

        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -1722,7 +1718,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        enforceCrossUserPermission(callingUid, userId,
                true,  // requireFullPermission
                true,  // checkShell
                false, // requirePermissionWhenSameUser
                "revokeRuntimePermission");

        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -4494,25 +4489,22 @@ public class PermissionManagerService extends IPermissionManager.Stub {
    }

    /**
     * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
     * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
     *
     * @param checkShell whether to prevent shell from access if there's a debugging restriction
     * @param message the message to log on security exception
     */
    private void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
            boolean requireFullPermission, boolean checkShell,
            boolean requirePermissionWhenSameUser, String message) {
            boolean requireFullPermission, boolean checkShell, @Nullable String message) {
        if (userId < 0) {
            throw new IllegalArgumentException("Invalid userId " + userId);
        }
        if (checkShell) {
            PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
                    UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
            enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
        }
        final int callingUserId = UserHandle.getUserId(callingUid);
        if (hasCrossUserPermission(
                callingUid, callingUserId, userId, requireFullPermission,
                requirePermissionWhenSameUser)) {
        if (checkCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission)) {
            return;
        }
        String errorMessage = buildInvalidCrossUserPermissionMessage(
@@ -4522,82 +4514,45 @@ public class PermissionManagerService extends IPermissionManager.Stub {
    }

    /**
     * Checks if the request is from the system or an app that has the appropriate cross-user
     * permissions defined as follows:
     * <ul>
     * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
     * <li>INTERACT_ACROSS_USERS if the given {@userId} is in a different profile group
     * to the caller.</li>
     * <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@userId} is in the same profile group
     * as the caller.</li>
     * </ul>
     *
     * @param checkShell whether to prevent shell from access if there's a debugging restriction
     * @param message the message to log on security exception
     *  Enforces that if the caller is shell, it does not have the provided user restriction.
     */
    private void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
            boolean requireFullPermission, boolean checkShell,
            String message) {
        if (userId < 0) {
            throw new IllegalArgumentException("Invalid userId " + userId);
        }
        if (checkShell) {
            PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
                    UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
        }
        final int callingUserId = UserHandle.getUserId(callingUid);
        if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
                /*requirePermissionWhenSameUser= */ false)) {
            return;
    private void enforceShellRestriction(@NonNull String restriction, int callingUid,
            @UserIdInt int userId) {
        if (callingUid == Process.SHELL_UID) {
            if (userId >= 0 && mUserManagerInt.hasUserRestriction(restriction, userId)) {
                throw new SecurityException("Shell does not have permission to access user "
                        + userId);
            } else if (userId < 0) {
                Slog.e(LOG_TAG, "Unable to check shell permission for user "
                        + userId + "\n\t" + Debug.getCallers(3));
            }
        final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
        if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
                mContext,
                android.Manifest.permission.INTERACT_ACROSS_PROFILES,
                PermissionChecker.PID_UNKNOWN,
                callingUid,
                mPackageManagerInt.getPackage(callingUid).getPackageName())
                == PermissionChecker.PERMISSION_GRANTED) {
            return;
        }
        String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
                callingUid, userId, message, requireFullPermission, isSameProfileGroup);
        Slog.w(TAG, errorMessage);
        throw new SecurityException(errorMessage);
    }

    private boolean hasCrossUserPermission(
            int callingUid, int callingUserId, int userId, boolean requireFullPermission,
            boolean requirePermissionWhenSameUser) {
        if (!requirePermissionWhenSameUser && userId == callingUserId) {
    private boolean checkCrossUserPermission(int callingUid, @UserIdInt int callingUserId,
            @UserIdInt int userId, boolean requireFullPermission) {
        if (userId == callingUserId) {
            return true;
        }
        if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
            return true;
        }
        if (requireFullPermission) {
            return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
            return checkCallingOrSelfPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        }
        return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
        return checkCallingOrSelfPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                || checkCallingOrSelfPermission(android.Manifest.permission.INTERACT_ACROSS_USERS);
    }

    private boolean hasPermission(String permission) {
    private boolean checkCallingOrSelfPermission(String permission) {
        return mContext.checkCallingOrSelfPermission(permission)
                == PackageManager.PERMISSION_GRANTED;
    }

    private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
        final long identity = Binder.clearCallingIdentity();
        try {
            return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    @NonNull
    private static String buildInvalidCrossUserPermissionMessage(int callingUid,
            @UserIdInt int userId, String message, boolean requireFullPermission) {
            @UserIdInt int userId, @Nullable String message, boolean requireFullPermission) {
        StringBuilder builder = new StringBuilder();
        if (message != null) {
            builder.append(message);
@@ -4617,31 +4572,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        return builder.toString();
    }

    private static String buildInvalidCrossUserOrProfilePermissionMessage(int callingUid,
            @UserIdInt int userId, String message, boolean requireFullPermission,
            boolean isSameProfileGroup) {
        StringBuilder builder = new StringBuilder();
        if (message != null) {
            builder.append(message);
            builder.append(": ");
        }
        builder.append("UID ");
        builder.append(callingUid);
        builder.append(" requires ");
        builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        if (!requireFullPermission) {
            builder.append(" or ");
            builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
            if (isSameProfileGroup) {
                builder.append(" or ");
                builder.append(android.Manifest.permission.INTERACT_ACROSS_PROFILES);
            }
        }
        builder.append(" to access user ");
        builder.append(".");
        return builder.toString();
    }

    @GuardedBy("mLock")
    private int calculateCurrentPermissionFootprintLocked(@NonNull Permission permissionTree) {
        int size = 0;
@@ -5140,30 +5070,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            Preconditions.checkArgumentNonNegative(userId, "userId");
            mPackageManagerInt.forEachPackage(pkg -> resetRuntimePermissionsInternal(pkg, userId));
        }
        @Override
        public void enforceCrossUserPermission(int callingUid, int userId,
                boolean requireFullPermission, boolean checkShell, String message) {
            PermissionManagerService.this.enforceCrossUserPermission(callingUid, userId,
                    requireFullPermission, checkShell, false, message);
        }
        @Override
        public void enforceCrossUserPermission(int callingUid, int userId,
                boolean requireFullPermission, boolean checkShell,
                boolean requirePermissionWhenSameUser, String message) {
            PermissionManagerService.this.enforceCrossUserPermission(callingUid, userId,
                    requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
        }

        @Override
        public void enforceCrossUserOrProfilePermission(int callingUid, int userId,
                boolean requireFullPermission, boolean checkShell, String message) {
            PermissionManagerService.this.enforceCrossUserOrProfilePermission(
                    callingUid,
                    userId,
                    requireFullPermission,
                    checkShell,
                    message);
        }

        @Override
        public Permission getPermissionTEMP(String permName) {
+0 −26
Original line number Diff line number Diff line
@@ -393,32 +393,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
    @NonNull
    public abstract String[] getAppOpPermissionPackages(@NonNull String permissionName);

    /**
     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userid} is not for the caller.
     * @param checkShell whether to prevent shell from access if there's a debugging restriction
     * @param message the message to log on security exception
     */
    public abstract void enforceCrossUserPermission(int callingUid, int userId,
            boolean requireFullPermission, boolean checkShell, @NonNull String message);

    /**
     * Similar to {@link #enforceCrossUserPermission(int, int, boolean, boolean, String)}
     * but also allows INTERACT_ACROSS_PROFILES permission if calling user and {@code userId} are
     * in the same profile group.
     */
    public abstract void enforceCrossUserOrProfilePermission(int callingUid, int userId,
            boolean requireFullPermission, boolean checkShell, @NonNull String message);

    /**
     * @see #enforceCrossUserPermission(int, int, boolean, boolean, String)
     * @param requirePermissionWhenSameUser When {@code true}, still require the cross user
     * permission to be held even if the callingUid and userId reference the same user.
     */
    public abstract void enforceCrossUserPermission(int callingUid, int userId,
            boolean requireFullPermission, boolean checkShell,
            boolean requirePermissionWhenSameUser, @NonNull String message);

    /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
    @Nullable
    public abstract Permission getPermissionTEMP(@NonNull String permName);
+7 −10
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm.test.override

import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.parsing.component.ParsedActivity
import android.os.Binder
import android.os.UserHandle
@@ -31,7 +32,6 @@ import com.android.server.pm.UserManagerService
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.parsing.pkg.ParsedPackage
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
@@ -45,11 +45,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.mockito.Mockito
import org.mockito.Mockito.any
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.anyString
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.intThat
import org.mockito.Mockito.never
@@ -321,10 +318,6 @@ class PackageManagerComponentLabelIconOverrideTest {
            whenever(this.exists(intThat(matcher))) { true }
            whenever(this.isUserUnlockingOrUnlocked(intThat(matcher))) { true }
        }
        val mockPermissionManagerService: PermissionManagerServiceInternal = mockThrowOnUnmocked {
            whenever(this.enforceCrossUserPermission(anyInt(), anyInt(), anyBoolean(), anyBoolean(),
                    anyString())) { }
        }
        val mockActivityTaskManager: ActivityTaskManagerInternal = mockThrowOnUnmocked {
            whenever(this.isCallerRecents(anyInt())) { false }
        }
@@ -335,15 +328,19 @@ class PackageManagerComponentLabelIconOverrideTest {
        val mockContext: Context = mockThrowOnUnmocked {
            whenever(this.getString(
                    com.android.internal.R.string.config_overrideComponentUiPackage)) { VALID_PKG }
            whenever(this.checkCallingOrSelfPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
                PackageManager.PERMISSION_GRANTED
            }
        }
        val mockInjector: PackageManagerService.Injector = mock {
            whenever(this.lock) { Object() }
            whenever(this.componentResolver) { mockComponentResolver }
            whenever(this.userManagerService) { mockUserManagerService }
            whenever(this.permissionManagerServiceInternal) { mockPermissionManagerService }
            whenever(this.settings) { mockSettings }
            whenever(this.getLocalService(ActivityTaskManagerInternal::class.java)) {
                mockActivityTaskManager}
                mockActivityTaskManager
            }
            whenever(this.appsFilter) { mockAppsFilter }
            whenever(this.context) { mockContext }
        }