Allowlist for platform signed package/sharedUid-s.
Fixes: 308573259
Test: atest android.content.pm.cts.PackageManagerTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4f882ccfbf955b5fc9e04ef45ff3293885a7d20a)
Merged-In: Ieb9e256b5fbb3b2ccd5d6a695f63011a31e95d9b
Change-Id: Ieb9e256b5fbb3b2ccd5d6a695f63011a31e95d9b
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 5e9d8f0..610057b 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -208,6 +208,14 @@
}
flag {
+ name: "restrict_nonpreloads_system_shareduids"
+ namespace: "package_manager_service"
+ description: "Feature flag to restrict apps from joining system shared uids"
+ bug: "308573169"
+ is_fixed_read_only: true
+}
+
+flag {
name: "min_target_sdk_24"
namespace: "responsible_apis"
description: "Feature flag to bump min target sdk to 24"
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 238a3e1..1410950 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -72,6 +72,12 @@
src: "enhanced-confirmation.xml",
}
+prebuilt_etc {
+ name: "package-shareduid-allowlist.xml",
+ sub_dir: "sysconfig",
+ src: "package-shareduid-allowlist.xml",
+}
+
// Privapp permission whitelist files
prebuilt_etc {
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
index 783a7ed..fd38d27 100644
--- a/data/etc/CleanSpec.mk
+++ b/data/etc/CleanSpec.mk
@@ -43,6 +43,8 @@
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/sysconfig/package-shareduid-allowlist.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/sysconfig/package-shareduid-allowlist.xml)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml)
diff --git a/data/etc/package-shareduid-allowlist.xml b/data/etc/package-shareduid-allowlist.xml
new file mode 100644
index 0000000..2401d4a
--- /dev/null
+++ b/data/etc/package-shareduid-allowlist.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!--
+This XML defines an allowlist for packages that want to join a particular shared-uid.
+If a non-system package that is signed with platform signature, is trying to join a particular
+shared-uid, and not in this list, the installation will fail.
+
+- The "package" XML attribute refers to the app's package name.
+- The "shareduid" XML attribute refers to the shared uid name.
+
+Example usage
+ 1. <allow-package-shareduid package="com.example.app" shareduid="android.uid.system"/>
+ Indicates that a package - com.example.app, will be able to join android.uid.system.
+ 2. <allow-package-shareduid package="oem.example.app" shareduid="oem.uid.custom"/>
+ Indicates that a package - oem.example.app, will be able to join oem.uid.custom.
+-->
+
+<config>
+ <allow-package-shareduid package="android.test.settings" shareduid="android.uid.system" />
+</config>
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 9189ea7..e1d7be1 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -348,6 +348,9 @@
// marked as stopped by the system
@NonNull private final Set<String> mInitialNonStoppedSystemPackages = new ArraySet<>();
+ // Which packages (key) are allowed to join particular SharedUid (value).
+ @NonNull private final Map<String, String> mPackageToSharedUidAllowList = new ArrayMap<>();
+
// A map of preloaded package names and the path to its app metadata file path.
private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>();
@@ -567,6 +570,11 @@
return mInitialNonStoppedSystemPackages;
}
+ @NonNull
+ public Map<String, String> getPackageToSharedUidAllowList() {
+ return mPackageToSharedUidAllowList;
+ }
+
public ArrayMap<String, String> getAppMetadataFilePaths() {
return mAppMetadataFilePaths;
}
@@ -1563,6 +1571,19 @@
mInitialNonStoppedSystemPackages.add(pkgName);
}
} break;
+ case "allow-package-shareduid": {
+ String pkgName = parser.getAttributeValue(null, "package");
+ String sharedUid = parser.getAttributeValue(null, "shareduid");
+ if (TextUtils.isEmpty(pkgName)) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if (TextUtils.isEmpty(sharedUid)) {
+ Slog.w(TAG, "<" + name + "> without shareduid in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mPackageToSharedUidAllowList.put(pkgName, sharedUid);
+ }
+ }
case "asl-file": {
String packageName = parser.getAttributeValue(null, "package");
String path = parser.getAttributeValue(null, "path");
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index ef9acc4..89c4f0f 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1080,7 +1080,7 @@
reconciledPackages = ReconcilePackageUtils.reconcilePackages(
requests, Collections.unmodifiableMap(mPm.mPackages),
versionInfos, mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
- mPm.mSettings);
+ mPm.mSettings, mPm.mInjector.getSystemConfig());
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.setError("Reconciliation failed...", e);
@@ -3811,7 +3811,7 @@
mPm.mPackages, Collections.singletonMap(pkgName,
mPm.getSettingsVersionForPackage(parsedPackage)),
mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
- mPm.mSettings);
+ mPm.mSettings, mPm.mInjector.getSystemConfig());
if ((scanFlags & SCAN_AS_APEX) == 0) {
appIdCreated = optimisticallyRegisterAppId(installRequest);
} else {
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 9a7916a..90d6adc 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
@@ -25,6 +26,7 @@
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
import static com.android.server.pm.PackageManagerService.TAG;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
@@ -36,6 +38,7 @@
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.SystemConfig;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.utils.WatchedLongSparseArray;
@@ -53,14 +56,17 @@
* as install) led to the request.
*/
final class ReconcilePackageUtils {
- private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true;
+ // TODO(b/308573259): with allow-list, we should be able to disallow such installs even in
+ // debuggable builds.
+ private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SHAREDUIDS = Build.IS_DEBUGGABLE
+ || !Flags.restrictNonpreloadsSystemShareduids();
public static List<ReconciledPackage> reconcilePackages(
List<InstallRequest> installRequests,
Map<String, AndroidPackage> allPackages,
Map<String, Settings.VersionInfo> versionInfos,
SharedLibrariesImpl sharedLibraries,
- KeySetManagerService ksms, Settings settings)
+ KeySetManagerService ksms, Settings settings, SystemConfig systemConfig)
throws ReconcileFailure {
final List<ReconciledPackage> result = new ArrayList<>(installRequests.size());
@@ -187,11 +193,19 @@
SigningDetails.CertCapabilities.PERMISSION)) {
Slog.d(TAG, "Non-preload app associated with system signature: "
+ signatureCheckPs.getPackageName());
- if (!ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE) {
- throw new ReconcileFailure(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- "Non-preload app associated with system signature: "
- + signatureCheckPs.getPackageName());
+ if (sharedUserSetting != null && !ALLOW_NON_PRELOADS_SYSTEM_SHAREDUIDS) {
+ // Check the allow-list.
+ var allowList = systemConfig.getPackageToSharedUidAllowList();
+ var sharedUidName = allowList.get(signatureCheckPs.getPackageName());
+ if (sharedUidName == null
+ || !sharedUserSetting.name.equals(sharedUidName)) {
+ var msg = "Non-preload app " + signatureCheckPs.getPackageName()
+ + " signed with platform signature and joining shared uid: "
+ + sharedUserSetting.name;
+ Slog.e(TAG, msg + ", allowList: " + allowList);
+ throw new ReconcileFailure(
+ INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, msg);
+ }
}
}