From e70b29e81010a871fbc7003eac0d1bd4ceaa7c2d Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Tue, 3 Apr 2018 16:44:39 -0700 Subject: [PATCH] Fix launcher apps reverse access Trying to access other profiles from work profile shouldn't throw security exception. This is a partial revert of Ia4ddea58f66861ef760865b6d8831563584f85c9. (Technically we should check the target user-id too, but that part isn't a regression, so I'm not fixing that part.) Bug: 77260666 Change-Id: I3f1f6584fcd6b879943d85ab4678b6130def0ba3 Fixes: 77260666 Test: atest /android/pi-dev/cts/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java#testReverseAccessNoThrow Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest1 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest2 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest3 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest4 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest5 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest6 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest7 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest8 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest9 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest10 -w com.android.frameworks.servicestests --- .../server/pm/LauncherAppsService.java | 20 ++++++++++++++++ .../server/pm/BaseShortcutManagerTest.java | 23 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 8e78703f37c2f..595de9e35a7f7 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -39,6 +39,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; +import android.content.pm.UserInfo; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -49,6 +50,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; +import android.os.UserManager; import android.os.UserManagerInternal; import android.provider.Settings; import android.util.Log; @@ -101,6 +103,7 @@ public class LauncherAppsService extends SystemService { private static final boolean DEBUG = false; private static final String TAG = "LauncherAppsService"; private final Context mContext; + private final UserManager mUm; private final UserManagerInternal mUserManagerInternal; private final ActivityManagerInternal mActivityManagerInternal; private final ShortcutServiceInternal mShortcutServiceInternal; @@ -113,6 +116,7 @@ public class LauncherAppsService extends SystemService { public LauncherAppsImpl(Context context) { mContext = context; + mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mUserManagerInternal = Preconditions.checkNotNull( LocalServices.getService(UserManagerInternal.class)); mActivityManagerInternal = Preconditions.checkNotNull( @@ -233,6 +237,22 @@ public class LauncherAppsService extends SystemService { * group. */ private boolean canAccessProfile(int targetUserId, String message) { + final int callingUserId = injectCallingUserId(); + + if (targetUserId == callingUserId) return true; + + long ident = injectClearCallingIdentity(); + try { + final UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); + if (callingUserInfo != null && callingUserInfo.isManagedProfile()) { + Slog.w(TAG, message + " for another profile " + + targetUserId + " from " + callingUserId + " not allowed"); + return false; + } + } finally { + injectRestoreCallingIdentity(ident); + } + return mUserManagerInternal.isProfileAccessible(injectCallingUserId(), targetUserId, message, true); } diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 197475032ea87..a6e0a662ffbcf 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -92,6 +92,8 @@ import com.android.server.pm.ShortcutUser.PackageWithUser; import org.junit.Assert; import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -111,6 +113,7 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Function; public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected static final String TAG = "ShortcutManagerTest"; @@ -834,6 +837,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { + targetUserId); }); + when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( + inv -> mUserInfos.get((Integer) inv.getArguments()[0]))); when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn( ActivityManager.PROCESS_STATE_CACHED_EMPTY); @@ -863,6 +868,24 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } } + /** + * Returns a boolean but also checks if the current UID is SYSTEM_UID. + */ + protected class AnswerWithSystemCheck implements Answer { + private final Function mChecker; + + public AnswerWithSystemCheck(Function checker) { + mChecker = checker; + } + + @Override + public T answer(InvocationOnMock invocation) throws Throwable { + assertEquals("Must be called on SYSTEM UID.", + Process.SYSTEM_UID, mInjectedCallingUid); + return mChecker.apply(invocation); + } + } + private static boolean b(Boolean value) { return (value != null && value); }