Fix cross user package visibility leakage for filterAppAccess API
- To fix apis which invoke the #filterAppAccess leak the package
existence information of other users, this CL returns true if
the target package is not installed under the given user id.
- Add an extra boolean parameter to the #filterAppAccess API for
the LauncherApp module to not filter the uninstalled package
when monitoring package changes events.
- Correct wrong user id usages of the filterAppAccess API in
some modules.
Bug: 229684723
Test: atest android.content.pm.cts.PackageManagerTest
Test: atest android.appenumeration.cts.AppEnumerationTests
Test: atest android.appwidget.cts.AppWidgetTest
Test: atest com.android.cts.devicepolicy.ManagedProfileCrossProfileTest
Test: atest com.android.cts.devicepolicy.LauncherAppsProfileTest
Test: atest android.devicepolicy.cts.LauncherAppsTests
Change-Id: I3cced4668d1cc4488665c928e4cbe4e194c249cf
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 40110e7..9466a31 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1695,7 +1695,7 @@
&& mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed(
providerPackageName, providerProfileId)
&& !mPackageManagerInternal.filterAppAccess(providerPackageName, callingUid,
- userId)) {
+ profileId)) {
result.add(cloneIfLocalBinder(info));
}
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 7cb7c0b..6063668 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -737,28 +737,49 @@
public abstract @Nullable String getInstantAppPackageName(int uid);
/**
- * Returns whether or not access to the application should be filtered.
+ * Returns whether or not access to the application should be filtered. The access is not
+ * allowed if the application is not installed under the given user.
* <p>
* Access may be limited based upon whether the calling or target applications
* are instant applications.
*
* @see #canAccessInstantApps
+ *
+ * @param pkg The package to be accessed.
+ * @param callingUid The uid that attempts to access the package.
+ * @param userId The user id where the package resides.
*/
public abstract boolean filterAppAccess(
@NonNull AndroidPackage pkg, int callingUid, int userId);
/**
- * Returns whether or not access to the application should be filtered.
+ * Returns whether or not access to the application should be filtered. The access is not
+ * allowed if the application is not installed under the given user.
*
* @see #filterAppAccess(AndroidPackage, int, int)
*/
+ public boolean filterAppAccess(@NonNull String packageName, int callingUid, int userId) {
+ return filterAppAccess(packageName, callingUid, userId, true /* filterUninstalled */);
+ }
+
+ /**
+ * Returns whether or not access to the application should be filtered.
+ *
+ * @param packageName The package to be accessed.
+ * @param callingUid The uid that attempts to access the package.
+ * @param userId The user id where the package resides.
+ * @param filterUninstalled Set to true to filter the access if the package is not installed
+ * under the given user.
+ * @see #filterAppAccess(AndroidPackage, int, int)
+ */
public abstract boolean filterAppAccess(
- @NonNull String packageName, int callingUid, int userId);
+ @NonNull String packageName, int callingUid, int userId, boolean filterUninstalled);
/**
* Returns whether or not access to the application which belongs to the given UID should be
* filtered. If the UID is part of a shared user ID, return {@code true} if all applications
- * belong to the shared user ID should be filtered.
+ * belong to the shared user ID should be filtered. The access is not allowed if the uid does
+ * not exist in the device.
*
* @see #filterAppAccess(AndroidPackage, int, int)
*/
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 5a2f6fe..b898b1c 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -305,7 +305,8 @@
SigningDetails getSigningDetails(@NonNull String packageName);
SigningDetails getSigningDetails(int uid);
boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
- boolean filterAppAccess(String packageName, int callingUid, int userId);
+ boolean filterAppAccess(String packageName, int callingUid, int userId,
+ boolean filterUninstalled);
boolean filterAppAccess(int uid, int callingUid);
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 5bdc9d8..31847bc 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -3162,30 +3162,31 @@
public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
PackageStateInternal ps = getPackageStateInternal(pkg.getPackageName());
- return shouldFilterApplication(ps, callingUid,
- userId);
+ return shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId);
}
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ public boolean filterAppAccess(String packageName, int callingUid, int userId,
+ boolean filterUninstalled) {
PackageStateInternal ps = getPackageStateInternal(packageName);
- return shouldFilterApplication(ps, callingUid,
- userId);
+ return shouldFilterApplication(
+ ps, callingUid, null /* component */, TYPE_UNKNOWN, userId, filterUninstalled);
}
public boolean filterAppAccess(int uid, int callingUid) {
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);
final Object setting = mSettings.getSettingBase(appId);
-
+ if (setting == null) {
+ return true;
+ }
if (setting instanceof SharedUserSetting) {
- return shouldFilterApplication(
+ return shouldFilterApplicationIncludingUninstalled(
(SharedUserSetting) setting, callingUid, userId);
- } else if (setting == null
- || setting instanceof PackageStateInternal) {
- return shouldFilterApplication(
+ } else if (setting instanceof PackageStateInternal) {
+ return shouldFilterApplicationIncludingUninstalled(
(PackageStateInternal) setting, callingUid, userId);
}
- return false;
+ return true;
}
public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index 20e4dd8..4134671 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -89,7 +89,8 @@
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return mPm.snapshotComputer().filterAppAccess(packageName, callingUid, userId);
+ return mPm.snapshotComputer().filterAppAccess(
+ packageName, callingUid, userId, true /* filterUninstalled */);
}
@Override
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 5e0fc3b..59bd427 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1358,10 +1358,19 @@
user.getIdentifier(), debugMsg, false);
}
- /** Returns whether or not the result to the listener should be filtered. */
- private boolean isPackageVisibleToListener(String packageName, BroadcastCookie cookie) {
+ /**
+ * Returns whether or not the result to the listener should be filtered.
+ *
+ * @param packageName The package to be accessed by the listener.
+ * @param cookie The listener
+ * @param user The user where the package resides.
+ */
+ private boolean isPackageVisibleToListener(String packageName, BroadcastCookie cookie,
+ UserHandle user) {
+ // Do not filter the uninstalled package access since it might break callbacks such as
+ // shortcut changes and unavailable packages events.
return !mPackageManagerInternal.filterAppAccess(packageName, cookie.callingUid,
- cookie.user.getIdentifier());
+ user.getIdentifier(), false /* filterUninstalled */);
}
/** Returns whether or not the given appId is in allow list */
@@ -1372,10 +1381,11 @@
return Arrays.binarySearch(appIdAllowList, appId) > -1;
}
- private String[] getFilteredPackageNames(String[] packageNames, BroadcastCookie cookie) {
+ private String[] getFilteredPackageNames(String[] packageNames, BroadcastCookie cookie,
+ UserHandle user) {
final List<String> filteredPackageNames = new ArrayList<>();
for (String packageName : packageNames) {
- if (!isPackageVisibleToListener(packageName, cookie)) {
+ if (!isPackageVisibleToListener(packageName, cookie, user)) {
continue;
}
filteredPackageNames.add(packageName);
@@ -1619,7 +1629,7 @@
if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) {
continue;
}
- if (!isPackageVisibleToListener(packageName, cookie)) {
+ if (!isPackageVisibleToListener(packageName, cookie, user)) {
continue;
}
try {
@@ -1653,7 +1663,7 @@
if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) {
continue;
}
- if (!isPackageVisibleToListener(packageName, cookie)) {
+ if (!isPackageVisibleToListener(packageName, cookie, user)) {
continue;
}
try {
@@ -1678,7 +1688,8 @@
if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) {
continue;
}
- final String[] filteredPackages = getFilteredPackageNames(packages, cookie);
+ final String[] filteredPackages =
+ getFilteredPackageNames(packages, cookie, user);
// If all packages are filtered, skip notifying listener.
if (ArrayUtils.isEmpty(filteredPackages)) {
continue;
@@ -1707,7 +1718,8 @@
if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) {
continue;
}
- final String[] filteredPackages = getFilteredPackageNames(packages, cookie);
+ final String[] filteredPackages =
+ getFilteredPackageNames(packages, cookie, user);
// If all packages are filtered, skip notifying listener.
if (ArrayUtils.isEmpty(filteredPackages)) {
continue;
@@ -1751,7 +1763,7 @@
continue;
}
final String[] filteredPackagesWithoutExtras =
- getFilteredPackageNames(packagesNullExtras, cookie);
+ getFilteredPackageNames(packagesNullExtras, cookie, user);
try {
if (!ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) {
listener.onPackagesSuspended(user, filteredPackagesWithoutExtras,
@@ -1759,7 +1771,8 @@
}
for (int idx = 0; idx < packagesWithExtras.size(); idx++) {
Pair<String, Bundle> packageExtraPair = packagesWithExtras.get(idx);
- if (!isPackageVisibleToListener(packageExtraPair.first, cookie)) {
+ if (!isPackageVisibleToListener(
+ packageExtraPair.first, cookie, user)) {
continue;
}
listener.onPackagesSuspended(user,
@@ -1786,7 +1799,8 @@
if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) {
continue;
}
- final String[] filteredPackages = getFilteredPackageNames(packages, cookie);
+ final String[] filteredPackages =
+ getFilteredPackageNames(packages, cookie, user);
// If all packages are filtered, skip notifying listener.
if (ArrayUtils.isEmpty(filteredPackages)) {
continue;
@@ -1822,7 +1836,7 @@
if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) {
continue;
}
- if (!isPackageVisibleToListener(packageName, cookie)) {
+ if (!isPackageVisibleToListener(packageName, cookie, user)) {
continue;
}
final int launcherUserId = cookie.user.getIdentifier();
@@ -1896,7 +1910,7 @@
if (!isEnabledProfileOf(cookie.user, mUser, "onLoadingProgressChanged")) {
continue;
}
- if (!isPackageVisibleToListener(mPackageName, cookie)) {
+ if (!isPackageVisibleToListener(mPackageName, cookie, mUser)) {
continue;
}
try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index b594866..c8db297 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -122,8 +122,9 @@
@Override
@Deprecated
- public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return snapshot().filterAppAccess(packageName, callingUid, userId);
+ public final boolean filterAppAccess(String packageName, int callingUid, int userId,
+ boolean filterUninstalled) {
+ return snapshot().filterAppAccess(packageName, callingUid, userId, filterUninstalled);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d545d41..ccd9066 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -524,7 +524,7 @@
final int callingUserId = UserHandle.getUserId(callingUid);
out.removeIf(it -> mPackageManagerInt.filterAppAccess(it.packageName, callingUid,
- callingUserId));
+ callingUserId, false /* filterUninstalled */));
return out;
}
@@ -549,7 +549,7 @@
final int callingUserId = UserHandle.getUserId(callingUid);
if (mPackageManagerInt.filterAppAccess(permissionGroupInfo.packageName, callingUid,
- callingUserId)) {
+ callingUserId, false /* filterUninstalled */)) {
EventLog.writeEvent(0x534e4554, "186113473", callingUid, groupName);
return null;
}
@@ -579,7 +579,7 @@
final int callingUserId = UserHandle.getUserId(callingUid);
if (mPackageManagerInt.filterAppAccess(permissionInfo.packageName, callingUid,
- callingUserId)) {
+ callingUserId, false /* filterUninstalled */)) {
EventLog.writeEvent(0x534e4554, "183122164", callingUid, permName);
return null;
}
@@ -624,11 +624,12 @@
final int callingUserId = UserHandle.getUserId(callingUid);
if (permissionGroup != null && mPackageManagerInt.filterAppAccess(
- permissionGroup.getPackageName(), callingUid, callingUserId)) {
+ permissionGroup.getPackageName(), callingUid, callingUserId,
+ false /* filterUninstalled */)) {
return null;
}
out.removeIf(it -> mPackageManagerInt.filterAppAccess(it.packageName, callingUid,
- callingUserId));
+ callingUserId, false /* filterUninstalled */));
return out;
}
@@ -710,7 +711,8 @@
if (pkg == null) {
return 0;
}
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId,
+ false /* filterUninstalled */)) {
return 0;
}
@@ -820,7 +822,8 @@
Log.e(TAG, "Unknown package: " + packageName);
return;
}
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId,
+ false /* filterUninstalled */)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -946,7 +949,8 @@
@NonNull String permissionName, @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (isPackageExplicit || pkg.getSharedUserId() == null) {
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ if (mPackageManagerInt.filterAppAccess(pkg.getPackageName(), callingUid, userId,
+ false /* filterUninstalled */)) {
return PackageManager.PERMISSION_DENIED;
}
} else {
@@ -1082,7 +1086,8 @@
}
final int callingUid = Binder.getCallingUid();
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, UserHandle.getCallingUserId())) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid,
+ UserHandle.getCallingUserId(), false /* filterUninstalled */)) {
return null;
}
final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
@@ -1196,7 +1201,8 @@
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- if (mPackageManagerInt.filterAppAccess(permissionPackageName, callingUid, callingUserId)) {
+ if (mPackageManagerInt.filterAppAccess(permissionPackageName, callingUid, callingUserId,
+ false /* filterUninstalled */)) {
EventLog.writeEvent(0x534e4554, "186404356", callingUid, permName);
return false;
}
@@ -1254,7 +1260,8 @@
}
final int callingUid = Binder.getCallingUid();
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, UserHandle.getCallingUserId())) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid,
+ UserHandle.getCallingUserId(), false /* filterUninstalled */)) {
return false;
}
@@ -1353,7 +1360,8 @@
Log.e(TAG, "Unknown package: " + packageName);
return;
}
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId,
+ false /* filterUninstalled */)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -1550,7 +1558,8 @@
Log.e(TAG, "Unknown package: " + packageName);
return;
}
- if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId,
+ false /* filterUninstalled */)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -1966,7 +1975,8 @@
}
final int callingUid = Binder.getCallingUid();
- if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId)) {
+ if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId,
+ false /* filterUninstalled */)) {
return false;
}