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:
kholoud mohamed
2020-01-15 15:30:07 +00:00
parent 30bf54729b
commit 79a89f022d
9 changed files with 99 additions and 19 deletions

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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,

View File

@@ -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)

View File

@@ -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;

View File

@@ -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");

View File

@@ -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);

View File

@@ -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());

View File

@@ -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;