diff options
author | 2024-09-19 11:59:27 -0700 | |
---|---|---|
committer | 2024-12-12 17:47:12 -0800 | |
commit | 14d462f7d4272c5d5a1cbb9110dfc07b0742647b (patch) | |
tree | 39d988feeec66b6c79ae9b34bc6f5a794b91a742 | |
parent | 75d3ee72e32f0ff678c12f42035b5a25cacc3a82 (diff) |
Introduce a new API to fetch contentProviders based on callingUid
This API will take a caller's UID to fetch content providers available
to it. This will be used to prevent cross user access to content
providers.
Bug: 334024639
Test: atest CtsContentProviderMultiUserTest
Flag: android.content.pm.uid_based_provider_lookup
Change-Id: I430d87629a198a3e9dfe19f6ae1b7e01d4005e6d
-rw-r--r-- | core/api/system-current.txt | 2 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 13 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 15 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 19 | ||||
-rw-r--r-- | core/java/android/content/pm/flags.aconfig | 8 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 14 | ||||
-rw-r--r-- | data/etc/privapp-permissions-platform.xml | 3 | ||||
-rw-r--r-- | packages/PackageInstaller/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java | 17 | ||||
-rw-r--r-- | packages/Shell/AndroidManifest.xml | 3 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/Computer.java | 14 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/ComputerEngine.java | 32 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/IPackageManagerBase.java | 6 |
13 files changed, 145 insertions, 2 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index f0f0fc98881e..afa231a609b6 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -360,6 +360,7 @@ package android { field @Deprecated public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES"; field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE"; field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD"; + field @FlaggedApi("android.content.pm.uid_based_provider_lookup") public static final String RESOLVE_COMPONENT_FOR_UID = "android.permission.RESOLVE_COMPONENT_FOR_UID"; field public static final String RESTART_WIFI_SUBSYSTEM = "android.permission.RESTART_WIFI_SUBSYSTEM"; field @FlaggedApi("android.permission.flags.health_connect_backup_restore_permission_enabled") public static final String RESTORE_HEALTH_CONNECT_DATA_AND_SETTINGS = "android.permission.RESTORE_HEALTH_CONNECT_DATA_AND_SETTINGS"; field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS"; @@ -4241,6 +4242,7 @@ package android.content.pm { method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback); method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener); method public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName); + method @FlaggedApi("android.content.pm.uid_based_provider_lookup") @Nullable @RequiresPermission(android.Manifest.permission.RESOLVE_COMPONENT_FOR_UID) public android.content.pm.ProviderInfo resolveContentProviderForUid(@NonNull String, @NonNull android.content.pm.PackageManager.ComponentInfoFlags, int); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String); method public void sendDeviceCustomizationReadyBroadcast(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index da338474a448..2dead565fa85 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1751,6 +1751,19 @@ public class ApplicationPackageManager extends PackageManager { } } + /** @hide **/ + @Override + public ProviderInfo resolveContentProviderForUid(@NonNull String authority, + ComponentInfoFlags flags, int callingUid) { + try { + return mPM.resolveContentProviderForUid(authority, + updateFlagsForComponent(flags.getValue(), getUserId(), null), getUserId(), + callingUid); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override public List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) { return queryContentProviders(processName, uid, ComponentInfoFlags.of(flags)); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 9f898b823a76..e6ddbf466cae 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -196,6 +196,21 @@ interface IPackageManager { ProviderInfo resolveContentProvider(String name, long flags, int userId); /** + * Resolve content providers with a given authority, for a specific + * callingUid. + * + * @param authority Authority of the content provider + * @param flags Additional option flags to modify the data returned. + * @param userId Current user ID + * @param callingUid UID of the caller who's access to the content provider + is to be checked + * + * @return ProviderInfo of the resolved content provider. May return null + */ + ProviderInfo resolveContentProviderForUid(String authority, long flags, + int userId, int callingUid); + + /** * Retrieve sync information for all content providers. * * @param outNames Filled in with a list of the root names of the content diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 438a21b7942f..c16582f19c9b 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8349,6 +8349,25 @@ public abstract class PackageManager { } /** + * Resolve content providers with a given authority, for a specific callingUid. + * @param authority Authority of the content provider + * @param flags Additional option flags to modify the data returned. + * @param callingUid UID of the caller who's access to the content provider is to be checked + + * @return ProviderInfo of the resolved content provider. + * @hide + */ + @Nullable + @FlaggedApi(android.content.pm.Flags.FLAG_UID_BASED_PROVIDER_LOOKUP) + @RequiresPermission(Manifest.permission.RESOLVE_COMPONENT_FOR_UID) + @SystemApi + public ProviderInfo resolveContentProviderForUid(@NonNull String authority, + @NonNull ComponentInfoFlags flags, int callingUid) { + throw new UnsupportedOperationException( + "resolveContentProviderForUid not implemented in subclass"); + } + + /** * Retrieve content provider information. * <p> * <em>Note: unlike most other methods, an empty result set is indicated diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index 00ddae334ef2..434952c6cac5 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -368,3 +368,11 @@ flag { description: "Feature flag to remove the consumption of the hidden module status (ModuleInfo#IsHidden) in the Android source tree." bug: "363952383" } + +flag { + name: "uid_based_provider_lookup" + is_exported: true + namespace: "package_manager_service" + bug: "334024639" + description: "Feature flag to check whether a given UID can access a content provider" +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4a948dd91fb0..1fa612ef3732 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8780,6 +8780,20 @@ android:featureFlag="com.android.art.flags.executable_method_file_offsets" /> <!-- + @SystemApi + @FlaggedApi(android.content.pm.Flags.FLAG_UID_BASED_PROVIDER_LOOKUP) + Allows an app to resolve components (e.g ContentProviders) on behalf of + other UIDs + <p>Protection level: signature|privileged + @hide + --> + <permission + android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" + android:protectionLevel="signature|privileged" + android:featureFlag="android.content.pm.uid_based_provider_lookup" /> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> + + <!-- @TestApi Signature permission reserved for testing. This should never be used to gate any actual functionality. diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 2398e7134b34..f136e065a405 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -125,6 +125,7 @@ applications that come with the platform <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/> <permission name="android.permission.PACKAGE_USAGE_STATS"/> <permission name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER"/> + <permission name="android.permission.RESOLVE_COMPONENT_FOR_UID"/> </privapp-permissions> <privapp-permissions package="com.android.phone"> @@ -609,6 +610,8 @@ applications that come with the platform <permission name="android.permission.MANAGE_INTRUSION_DETECTION_STATE" /> <!-- Permission required for CTS test - KeyguardLockedStateApiTest --> <permission name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" /> + <!-- Permission required for CTS test - CtsContentProviderMultiUserTest --> + <permission name="android.permission.RESOLVE_COMPONENT_FOR_UID"/> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index e029f3a16066..4da73593bdea 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -24,6 +24,7 @@ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" /> <uses-permission android:name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER" /> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" /> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index 635ae20cfa38..6c06fab16502 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -26,6 +26,7 @@ import android.app.admin.DevicePolicyManager; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.Flags; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; @@ -274,8 +275,20 @@ public class InstallStart extends Activity { } private boolean canPackageQuery(int callingUid, Uri packageUri) { - ProviderInfo info = mPackageManager.resolveContentProvider(packageUri.getAuthority(), - PackageManager.ComponentInfoFlags.of(0)); + ProviderInfo info; + try { + if (Flags.uidBasedProviderLookup()) { + info = mPackageManager.resolveContentProviderForUid(packageUri.getAuthority(), + PackageManager.ComponentInfoFlags.of(0), callingUid); + } else { + info = mPackageManager.resolveContentProvider(packageUri.getAuthority(), + PackageManager.ComponentInfoFlags.of(0)); + } + } catch (Exception e) { + Log.e(TAG, "Caller cannot access " + packageUri, e); + return false; + } + if (info == null) { return false; } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index fb4293a9b5ea..46bd88fcdc93 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -994,6 +994,9 @@ <uses-permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE" android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/> + <!-- Permission required for CTS test - CtsContentProviderMultiUserTest --> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index 3528d3d96c2b..8a35006e0f6a 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -487,6 +487,20 @@ public interface Computer extends PackageDataSnapshot { ProviderInfo resolveContentProvider(@NonNull String name, @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid); + /** + * Resolves a ContentProvider on behalf of a UID + * @param name Authority of the content provider + * @param flags option flags to modify the data returned. + * @param userId Current user ID + * @param filterCallingUid UID of the caller who's access to the content provider + * is to be checked + * @return + */ + @Nullable + ProviderInfo resolveContentProviderForUid(@NonNull String name, + @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, + int filterCallingUid); + @Nullable ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid, @NonNull String visibleAuthority); diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index be2f58dc276c..38617621bf89 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -4749,6 +4749,38 @@ public class ComputerEngine implements Computer { @Nullable @Override + public ProviderInfo resolveContentProviderForUid(@NonNull String name, + @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, + int filterCallingUid) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.RESOLVE_COMPONENT_FOR_UID, + "resolveContentProviderForUid"); + + int callingUid = Binder.getCallingUid(); + int filterUserId = UserHandle.getUserId(filterCallingUid); + enforceCrossUserPermission(callingUid, filterUserId, false, false, + "resolveContentProviderForUid"); + + // Real callingUid should be able to see filterCallingUid + if (filterAppAccess(filterCallingUid, callingUid)) { + return null; + } + + ProviderInfo pInfo = resolveContentProvider(name, flags, userId, filterCallingUid); + if (pInfo == null) { + return null; + } + // Real callingUid should be able to see the ContentProvider accessible to filterCallingUid + ProviderInfo pInfo2 = resolveContentProvider(name, flags, userId, callingUid); + if (pInfo2 != null + && Objects.equals(pInfo.name, pInfo2.name) + && Objects.equals(pInfo.authority, pInfo2.authority)) { + return pInfo; + } + return null; + } + + @Nullable + @Override public ProviderInfo resolveContentProvider(@NonNull String name, @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid) { diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index f05c54d666df..b11d3499d391 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -1129,6 +1129,12 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { } @Override + public final ProviderInfo resolveContentProviderForUid(String name, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, int filterCallingUid) { + return snapshot().resolveContentProviderForUid(name, flags, userId, filterCallingUid); + } + + @Override @Deprecated public final void resetApplicationPreferences(int userId) { mPreferredActivityHelper.resetApplicationPreferences(userId); |