summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sumedh Sen <sumedhsen@google.com> 2024-09-19 11:59:27 -0700
committer Sumedh Sen <sumedhsen@google.com> 2024-12-12 17:47:12 -0800
commit14d462f7d4272c5d5a1cbb9110dfc07b0742647b (patch)
tree39d988feeec66b6c79ae9b34bc6f5a794b91a742
parent75d3ee72e32f0ff678c12f42035b5a25cacc3a82 (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.txt2
-rw-r--r--core/java/android/app/ApplicationPackageManager.java13
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl15
-rw-r--r--core/java/android/content/pm/PackageManager.java19
-rw-r--r--core/java/android/content/pm/flags.aconfig8
-rw-r--r--core/res/AndroidManifest.xml14
-rw-r--r--data/etc/privapp-permissions-platform.xml3
-rw-r--r--packages/PackageInstaller/AndroidManifest.xml1
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java17
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--services/core/java/com/android/server/pm/Computer.java14
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java32
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java6
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);