From 7d0ce7f7df943f15fe9ca15119c7ed48836671c8 Mon Sep 17 00:00:00 2001 From: Rhed Jao Date: Mon, 30 Aug 2021 19:15:21 +0800 Subject: [PATCH] Allow application to inspect query-ability of other package This CL creates a new API PackageManager#mayPackageQuery for applications that share details about other applications to determine if those details should be withheld from callers that do not otherwise have visibility of them. Bug: 145916881 Test: atest AppEnumerationTests Change-Id: I2dfba1169bce3d9fa88a75c92a22f53e1efe01b5 --- core/api/current.txt | 1 + .../app/ApplicationPackageManager.java | 15 +++++++++ .../android/content/pm/IPackageManager.aidl | 2 ++ .../android/content/pm/PackageManager.java | 25 +++++++++++++++ .../server/pm/PackageManagerService.java | 31 +++++++++++++++++++ 5 files changed, 74 insertions(+) diff --git a/core/api/current.txt b/core/api/current.txt index 29538ab0729fc..78c4cdfda40ca 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12631,6 +12631,7 @@ package android.content.pm { method public boolean isPackageSuspended(); method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String); method public abstract boolean isSafeMode(); + method public boolean mayPackageQuery(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method @NonNull public java.util.List queryActivityProperty(@NonNull String); method @NonNull public java.util.List queryApplicationProperty(@NonNull String); method @NonNull public abstract java.util.List queryBroadcastReceivers(@NonNull android.content.Intent, int); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 57de588f38843..7ddc2c94d8c91 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -3575,4 +3575,19 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public boolean mayPackageQuery(@NonNull String sourcePackageName, + @NonNull String targetPackageName) throws NameNotFoundException { + Objects.requireNonNull(sourcePackageName); + Objects.requireNonNull(targetPackageName); + try { + return mPM.mayPackageQuery(sourcePackageName, targetPackageName, getUserId()); + } catch (ParcelableException e) { + e.maybeRethrow(PackageManager.NameNotFoundException.class); + throw new RuntimeException(e); + } catch (RemoteException re) { + throw re.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 86030fdc1d72f..df292490e6ce3 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -818,4 +818,6 @@ interface IPackageManager { ParceledListSlice queryProperty(String propertyName, int componentType); void setKeepUninstalledPackages(in List packageList); + + boolean mayPackageQuery(String sourcePackageName, String targetPackageName, int userId); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 31b9c305f5a34..6b672ff183e8e 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -9329,6 +9329,31 @@ public abstract class PackageManager { "qeuryServiceProperty not implemented in subclass"); } + /** + * Returns {@code true} if the source package is able to query for details about the + * target package. Applications that share details about other applications should + * use this API to determine if those details should be withheld from callers that + * do not otherwise have visibility of them. + *

+ * Note: The caller must be able to query for details about the source and target + * package. A {@link NameNotFoundException} is thrown if it isn't. + * + * @param sourcePackageName The source package that would receive details about the + * target package. + * @param targetPackageName The target package whose details would be shared with the + * source package. + * @return {@code true} if the source package is able to query for details about the + * target package. + * @throws NameNotFoundException if either a given package can not be found on the + * system, or if the caller is not able to query for details about the source or + * target package. + */ + public boolean mayPackageQuery(@NonNull String sourcePackageName, + @NonNull String targetPackageName) throws NameNotFoundException { + throw new UnsupportedOperationException( + "mayPackageQuery not implemented in subclass"); + } + /** * Grants implicit visibility of the package that provides an authority to a querying UID. * diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2c2884f4e76f8..e2e10839883fa 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -23388,6 +23388,37 @@ public class PackageManagerService extends IPackageManager.Stub return new IntentSender(target); } + @Override + public boolean mayPackageQuery(String sourcePackageName, String targetPackageName, int userId) { + if (!mUserManager.exists(userId)) return false; + final int callingUid = Binder.getCallingUid(); + enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, + false /*checkShell*/, "may package query"); + synchronized (mLock) { + final PackageSetting sourceSetting = getPackageSetting(sourcePackageName); + final PackageSetting targetSetting = getPackageSetting(targetPackageName); + if (sourceSetting == null || targetSetting == null) { + throw new ParcelableException(new PackageManager.NameNotFoundException("Package(s) " + + (sourceSetting == null ? sourcePackageName + " " : "") + + (targetSetting == null ? targetPackageName + " " : "") + + "not found.")); + } + final boolean filterSource = + shouldFilterApplicationLocked(sourceSetting, callingUid, userId); + final boolean filterTarget = + shouldFilterApplicationLocked(targetSetting, callingUid, userId); + // The caller must have visibility of the both packages + if (filterSource || filterTarget) { + throw new ParcelableException(new PackageManager.NameNotFoundException("Package(s) " + + (filterSource ? sourcePackageName + " " : "") + + (filterTarget ? targetPackageName + " " : "") + + "not found.")); + } + final int sourcePackageUid = UserHandle.getUid(userId, sourceSetting.appId); + return !shouldFilterApplicationLocked(targetSetting, sourcePackageUid, userId); + } + } + private static class TempUserState { public final int enabledState; @Nullable