diff options
9 files changed, 99 insertions, 19 deletions
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index f3a2e70f9b89..afc3d918073e 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -54,6 +54,7 @@ import android.appwidget.AppWidgetManagerInternal; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; +import android.content.PermissionChecker; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.UserInfo; @@ -1756,7 +1757,7 @@ class UserController implements Handler.Callback { // We require full access, sucks to be you. allow = false; } else if (canInteractWithAcrossProfilesPermission( - allowMode, isSameProfileGroup, callingPid, callingUid)) { + allowMode, isSameProfileGroup, callingPid, callingUid, callerPackage)) { allow = true; } else if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS, callingPid, callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { @@ -1821,16 +1822,21 @@ class UserController implements Handler.Callback { } private boolean canInteractWithAcrossProfilesPermission( - int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid) { + int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid, + String callingPackage) { if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) { return false; } if (!isSameProfileGroup) { return false; } - return mInjector.checkComponentPermission( - INTERACT_ACROSS_PROFILES, callingPid, callingUid, /*owningUid= */-1, - /*exported= */true) == PackageManager.PERMISSION_GRANTED; + return PermissionChecker.PERMISSION_GRANTED + == PermissionChecker.checkPermissionForPreflight( + mInjector.getContext(), + INTERACT_ACROSS_PROFILES, + callingPid, + callingUid, + callingPackage); } int unsafeConvertIncomingUser(@UserIdInt int userId) { diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index bdc1b074920a..3635004987e8 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -35,6 +35,7 @@ import android.app.admin.DevicePolicyManagerInternal; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ICrossProfileApps; import android.content.pm.IPackageManager; @@ -114,6 +115,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { final int callerUserId = mInjector.getCallingUserId(); final int callingUid = mInjector.getCallingUid(); + final int callingPid = mInjector.getCallingPid(); List<UserHandle> allowedTargetUsers = getTargetUserProfilesUnchecked( callingPackage, callerUserId); @@ -143,10 +145,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { // must have the required permission and the users must be in the same profile group // in order to launch any of its own activities. if (callerUserId != userId) { - final int permissionFlag = mInjector.checkComponentPermission( - android.Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid, - -1, true); - if (permissionFlag != PackageManager.PERMISSION_GRANTED + final int permissionFlag = PermissionChecker.checkPermissionForPreflight( + mContext, + android.Manifest.permission.INTERACT_ACROSS_PROFILES, + callingPid, + callingUid, + callingPackage); + if (permissionFlag != PermissionChecker.PERMISSION_GRANTED || !isSameProfileGroup(callerUserId, userId)) { throw new SecurityException("Attempt to launch activity without required " + android.Manifest.permission.INTERACT_ACROSS_PROFILES + " permission" @@ -210,12 +215,15 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return false; } final int callingUid = mInjector.getCallingUid(); + final int callingPid = mInjector.getCallingPid(); return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid) || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid) - || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid) - || AppOpsManager.MODE_ALLOWED == getAppOpsService().noteOperation( - OP_INTERACT_ACROSS_PROFILES, callingUid, callingPackage, /* featureId= */ null, - /*shouldCollectAsyncNotedOp= */false, /*message= */null); + || PermissionChecker.checkPermissionForPreflight( + mContext, + Manifest.permission.INTERACT_ACROSS_PROFILES, + callingPid, + callingUid, + callingPackage) == PermissionChecker.PERMISSION_GRANTED; } private boolean isCrossProfilePackageWhitelisted(String packageName) { @@ -436,6 +444,10 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return Binder.getCallingUid(); } + public int getCallingPid() { + return Binder.getCallingPid(); + } + public int getCallingUserId() { return UserHandle.getCallingUserId(); } @@ -504,6 +516,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public interface Injector { int getCallingUid(); + int getCallingPid(); + int getCallingUserId(); UserHandle getCallingUserHandle(); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 0411e29f68a1..6167a509b85f 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -58,6 +58,7 @@ import android.app.IActivityManager; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.Context; +import android.content.PermissionChecker; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PermissionGroupInfoFlags; @@ -4070,8 +4071,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { return; } final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId); - if (isSameProfileGroup - && hasPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES)) { + 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( @@ -4349,7 +4355,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Override public void enforceCrossUserOrProfilePermission(int callingUid, int userId, boolean requireFullPermission, boolean checkShell, String message) { - PermissionManagerService.this.enforceCrossUserOrProfilePermission(callingUid, + PermissionManagerService.this.enforceCrossUserOrProfilePermission( + callingUid, userId, requireFullPermission, checkShell, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index af57c29fda82..ac85932e92f0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -9102,11 +9102,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void enforceAcrossUsersPermissions() { - if (isCallerWithSystemUid() || mInjector.binderGetCallingUid() == Process.ROOT_UID) { + final int callingUid = mInjector.binderGetCallingUid(); + final int callingPid = mInjector.binderGetCallingPid(); + final String packageName = mContext.getPackageName(); + + if (isCallerWithSystemUid() || callingUid == Process.ROOT_UID) { return; } - if (mContext.checkCallingPermission(permission.INTERACT_ACROSS_PROFILES) - == PackageManager.PERMISSION_GRANTED) { + if (PermissionChecker.checkPermissionForPreflight( + mContext, permission.INTERACT_ACROSS_PROFILES, callingPid, callingUid, + packageName) == PermissionChecker.PERMISSION_GRANTED) { return; } if (mContext.checkCallingPermission(permission.INTERACT_ACROSS_USERS) diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java index ce0886435906..96ff9c1ba726 100644 --- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java @@ -79,6 +79,7 @@ import java.util.Set; @Config(shadows = {ShadowUserManager.class, ShadowApplicationPackageManager.class}) public class CrossProfileAppsServiceImplRoboTest { private static final int CALLING_UID = 1111; + private static final int CALLING_PID = 1000; private static final String CROSS_PROFILE_APP_PACKAGE_NAME = "com.android.server.pm.crossprofileappsserviceimplrobotest.crossprofileapp"; private static final int PERSONAL_PROFILE_USER_ID = 0; @@ -383,6 +384,11 @@ public class CrossProfileAppsServiceImplRoboTest { } @Override + public int getCallingPid() { + return CALLING_PID; + } + + @Override public @UserIdInt int getCallingUserId() { return PERSONAL_PROFILE_USER_ID; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 632a2c1edfae..e70cd60c9e19 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -5678,6 +5678,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetAllCrossProfilePackages_notSet_returnsEmpty() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); + mContext.packageName = admin1.getPackageName(); setCrossProfileAppsList(); @@ -5687,6 +5688,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetAllCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); + mContext.packageName = admin1.getPackageName(); setCrossProfileAppsList(); initializeDpms(); @@ -5697,6 +5699,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testGetAllCrossProfilePackages_whenSet_returnsCombinedSet() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE"); + mContext.packageName = admin1.getPackageName(); dpm.setCrossProfilePackages(admin1, packages); setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); @@ -5711,6 +5714,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE"); + mContext.packageName = admin1.getPackageName(); dpm.setCrossProfilePackages(admin1, packages); setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 960f670904d6..6cf6b67430ae 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -219,6 +219,8 @@ public class DpmMockContext extends MockContext { return mMockSystemServices.accountManager; case Context.TELEPHONY_SERVICE: return mMockSystemServices.telephonyManager; + case Context.APP_OPS_SERVICE: + return mMockSystemServices.appOpsManager; } throw new UnsupportedOperationException(); } @@ -256,6 +258,22 @@ public class DpmMockContext extends MockContext { } @Override + public int checkPermission(String permission, int pid, int uid) { + if (UserHandle.isSameApp(binder.getCallingUid(), SYSTEM_UID)) { + return PackageManager.PERMISSION_GRANTED; // Assume system has all permissions. + } + List<String> permissions = binder.callingPermissions.get(binder.getCallingUid()); + if (permissions == null) { + permissions = callerPermissions; + } + if (permissions.contains(permission)) { + return PackageManager.PERMISSION_GRANTED; + } else { + return PackageManager.PERMISSION_DENIED; + } + } + + @Override public void sendBroadcast(Intent intent) { spiedContext.sendBroadcast(intent); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 068daf5ee310..b9fb1aab65ba 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -28,6 +28,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; +import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.app.NotificationManager; @@ -120,6 +121,7 @@ public class MockSystemServices { public final TimeZoneDetector timeZoneDetector; public final KeyChain.KeyChainConnection keyChainConnection; public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal; + public final AppOpsManager appOpsManager; /** Note this is a partial mock, not a real mock. */ public final PackageManager packageManager; public final BuildMock buildMock = new BuildMock(); @@ -164,6 +166,7 @@ public class MockSystemServices { timeZoneDetector = mock(TimeZoneDetector.class); keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS); persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class); + appOpsManager = mock(AppOpsManager.class); // Package manager is huge, so we use a partial mock instead. packageManager = spy(realContext.getPackageManager()); diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java index 68f60b4ff67a..91cc9f35da1e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java @@ -27,6 +27,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.PermissionInfo; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.os.UserHandle; @@ -95,6 +96,7 @@ public class CrossProfileAppsServiceImplTest { public void initCrossProfileAppsServiceImpl() { mTestInjector = new TestInjector(); mCrossProfileAppsServiceImpl = new CrossProfileAppsServiceImpl(mContext, mTestInjector); + when(mContext.getPackageManager()).thenReturn(mPackageManager); } @Before @@ -365,6 +367,11 @@ public class CrossProfileAppsServiceImplTest { @Test public void startAnyActivityAsUser_profile_notExported() { + try { + when(mPackageManager.getPermissionInfo(anyString(), anyInt())) + .thenReturn(new PermissionInfo()); + } catch (PackageManager.NameNotFoundException ignored) { + } mActivityInfo.exported = false; assertThrows( @@ -523,11 +530,16 @@ public class CrossProfileAppsServiceImplTest { private class TestInjector implements CrossProfileAppsServiceImpl.Injector { private int mCallingUid; private int mCallingUserId; + private int mCallingPid; public void setCallingUid(int uid) { mCallingUid = uid; } + public void setCallingPid(int pid) { + mCallingPid = pid; + } + public void setCallingUserId(int userId) { mCallingUserId = userId; } @@ -538,6 +550,11 @@ public class CrossProfileAppsServiceImplTest { } @Override + public int getCallingPid() { + return mCallingPid; + } + + @Override public int getCallingUserId() { return mCallingUserId; } |