diff options
author | Makoto Onuki <omakoto@google.com> | 2020-01-29 17:06:52 -0800 |
---|---|---|
committer | Makoto Onuki <omakoto@google.com> | 2020-01-30 13:32:26 -0800 |
commit | 782ce6c358bb4e5d652acced40931a5293dbec6d (patch) | |
tree | 46c61adb6e63fa2cc75b697ae991bda8a9dffc84 | |
parent | 6c3c7a19951358eb7f908059de61d3c248248601 (diff) | |
download | ContactsProvider-782ce6c358bb4e5d652acced40931a5293dbec6d.tar.gz |
Allow privileged apps to query contact provider across user
Callers with INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL
should be able to query contact provider for other users.
Fix: 138781676
Test: CTS verifier - Notification Attention Management Tests
on user-0 and a secondary user
Test: atest ContactsProviderTests
Test: atest ManagedProfileTest
Test: atest ManagedProfileContactsTest
Change-Id: Iac708de441b375a433dce04540b99546e0364021
-rw-r--r-- | src/com/android/providers/contacts/ContactsProvider2.java | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java index 352029d8..5159fb94 100644 --- a/src/com/android/providers/contacts/ContactsProvider2.java +++ b/src/com/android/providers/contacts/ContactsProvider2.java @@ -16,6 +16,10 @@ package com.android.providers.contacts; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; + import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; @@ -214,7 +218,6 @@ public class ContactsProvider2 extends AbstractContactsProvider private static final String READ_PERMISSION = "android.permission.READ_CONTACTS"; private static final String WRITE_PERMISSION = "android.permission.WRITE_CONTACTS"; - private static final String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS"; /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; @@ -5363,10 +5366,12 @@ public class ContactsProvider2 extends AbstractContactsProvider return null; } - // Check enterprise policy if caller does not come from same profile - if (!(isCallerFromSameUser() || mEnterprisePolicyGuard.isCrossProfileAllowed(uri))) { - return createEmptyCursor(uri, projection); + // If caller does not come from same profile, Check if it's privileged or allowed by + // enterprise policy + if (!queryAllowedByEnterprisePolicy(uri)) { + return null; } + // Query the profile DB if appropriate. if (mapsToProfileDb(uri)) { switchToProfileMode(); @@ -5386,9 +5391,46 @@ public class ContactsProvider2 extends AbstractContactsProvider } } + private boolean queryAllowedByEnterprisePolicy(Uri uri) { + if (isCallerFromSameUser()) { + // Caller is on the same user; query allowed. + return true; + } + if (!doesCallerHoldInteractAcrossUserPermission()) { + // Cross-user and the caller has no INTERACT_ACROSS_USERS; don't allow query. + // Technically, in a cross-profile sharing case, this would be a valid query. + // But for now we don't allow it. (We never allowe it and no one complained about it.) + return false; + } + if (isCallerAnotherSelf()) { + // The caller is the other CP2 (which has INTERACT_ACROSS_USERS), meaning the reuest + // is on behalf of a "real" client app. + // Consult the enterprise policy. + return mEnterprisePolicyGuard.isCrossProfileAllowed(uri); + } + return true; + } + private boolean isCallerFromSameUser() { - return Binder.getCallingUserHandle().getIdentifier() == UserUtils - .getCurrentUserHandle(getContext()); + return UserHandle.getUserId(Binder.getCallingUid()) == UserHandle.myUserId(); + } + + /** + * Returns true if called by a different user's CP2. + */ + private boolean isCallerAnotherSelf() { + // Note normally myUid is always different from the callerUid in the code path where + // this method is used, except during unit tests, where the caller is always the same + // process. + final int myUid = android.os.Process.myUid(); + final int callingUid = Binder.getCallingUid(); + return (myUid != callingUid) && UserHandle.isSameApp(myUid, callingUid); + } + + private boolean doesCallerHoldInteractAcrossUserPermission() { + final Context context = getContext(); + return context.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) == PERMISSION_GRANTED + || context.checkCallingPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED; } private Cursor queryDirectoryIfNecessary(Uri uri, String[] projection, String selection, @@ -5435,7 +5477,7 @@ public class ContactsProvider2 extends AbstractContactsProvider private String getRealCallerPackageName(Uri queryUri) { // If called by another CP2, then the URI should contain the original package name. - if (calledByAnotherSelf()) { + if (isCallerAnotherSelf()) { final String passedPackage = queryUri.getQueryParameter( Directory.CALLER_PACKAGE_PARAM_KEY); if (TextUtils.isEmpty(passedPackage)) { @@ -5450,18 +5492,6 @@ public class ContactsProvider2 extends AbstractContactsProvider } } - /** - * Returns true if called by a different user's CP2. - */ - private boolean calledByAnotherSelf() { - // Note normally myUid is always different from the callerUid in the code path where - // this method is used, except during unit tests, where the caller is always the same - // process. - final int myUid = android.os.Process.myUid(); - final int callerUid = Binder.getCallingUid(); - return (myUid != callerUid) && UserHandle.isSameApp(myUid, callerUid); - } - private Cursor queryDirectoryAuthority(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, String directory, final CancellationSignal cancellationSignal) { @@ -8434,9 +8464,7 @@ public class ContactsProvider2 extends AbstractContactsProvider if (!isDirectoryParamValid(uri)){ return null; } - if (!isCallerFromSameUser() /* From differnt user */ - && !mEnterprisePolicyGuard.isCrossProfileAllowed(uri) - /* Policy not allowed */){ + if (!queryAllowedByEnterprisePolicy(uri)) { return null; } waitForAccess(mode.equals("r") ? mReadAccessLatch : mWriteAccessLatch); |