Add a checks for _ACROSS_PROFILES apppop or permission.
Use hasPermissionOrAppOpForPreflight to check for INTERACT_ACROSS_PROFILES permission or appop rather than only checking for the permission. BUG: 140728653 BUG: 136249261 Test: atest CrossProfileAppsPermissionHostSideTest Test: atest CrossProfileAppsHostSideTest Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest Test: atest ContextCrossProfileHostTest Change-Id: I81d428d47afd54f294ef9bb44133004762840d09
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
@@ -382,6 +383,11 @@ public class CrossProfileAppsServiceImplRoboTest {
|
||||
return CALLING_UID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallingPid() {
|
||||
return CALLING_PID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @UserIdInt int getCallingUserId() {
|
||||
return PERSONAL_PROFILE_USER_ID;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -255,6 +257,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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -537,6 +549,11 @@ public class CrossProfileAppsServiceImplTest {
|
||||
return mCallingUid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallingPid() {
|
||||
return mCallingPid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallingUserId() {
|
||||
return mCallingUserId;
|
||||
|
||||
Reference in New Issue
Block a user