Loading data/etc/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,12 @@ prebuilt_etc { src: "preinstalled-packages-asl-files.xml", } prebuilt_etc { name: "preinstalled-packages-strict-signature.xml", sub_dir: "sysconfig", src: "preinstalled-packages-strict-signature.xml", } // Privapp permission whitelist files prebuilt_etc { Loading data/etc/preinstalled-packages-strict-signature.xml 0 → 100644 +27 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 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 file declares which preinstalled apps, after updated, need to have strict signature check in boot time and avoid the cached results. This is to ensure the updated version still verifies against the preinstalled version. Example usage: <require-strict-signature package="com.foo.bar"/> --> <config></config> services/core/java/com/android/server/SystemConfig.java +19 −0 Original line number Diff line number Diff line Loading @@ -340,6 +340,10 @@ public class SystemConfig { // A map of preloaded package names and the path to its app metadata file path. private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>(); // A set of pre-installed package names that requires strict signature verification once // updated to avoid cached/potentially tampered results. private final Set<String> mPreinstallPackagesWithStrictSignatureCheck = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, * value maps actor name to package name. Loading Loading @@ -542,6 +546,10 @@ public class SystemConfig { return mAppMetadataFilePaths; } public Set<String> getPreinstallPackagesWithStrictSignatureCheck() { return mPreinstallPackagesWithStrictSignatureCheck; } /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. Loading Loading @@ -1485,6 +1493,17 @@ public class SystemConfig { mAppMetadataFilePaths.put(packageName, path); } } break; case "require-strict-signature": { if (android.security.Flags.extendVbChainToUpdatedApk()) { String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { Slog.w(TAG, "<" + name + "> without valid package in " + permFile + " at " + parser.getPositionDescription()); } else { mPreinstallPackagesWithStrictSignatureCheck.add(packageName); } } } break; default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); Loading services/core/java/com/android/server/pm/InstallPackageHelper.java +31 −24 Original line number Diff line number Diff line Loading @@ -3728,7 +3728,7 @@ final class InstallPackageHelper { final ScanResult scanResult = scanResultPair.first; boolean shouldHideSystemApp = scanResultPair.second; final InstallRequest installRequest = new InstallRequest( parsedPackage, parseFlags, scanFlags, user, scanResult); parsedPackage, parseFlags, scanFlags, user, scanResult, disabledPkgSetting); String existingApexModuleName = null; synchronized (mPm.mLock) { Loading Loading @@ -3962,6 +3962,7 @@ final class InstallPackageHelper { final String disabledPkgName = pkgAlreadyExists ? pkgSetting.getPackageName() : parsedPackage.getPackageName(); final boolean isSystemPkgUpdated; final PackageSetting disabledPkgSetting; final boolean isUpgrade; synchronized (mPm.mLock) { isUpgrade = mPm.isDeviceUpgrading(); Loading @@ -3975,8 +3976,7 @@ final class InstallPackageHelper { + "and install it as non-updated system app."); mPm.mSettings.removeDisabledSystemPackageLPw(disabledPkgName); } final PackageSetting disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName); disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName); isSystemPkgUpdated = disabledPkgSetting != null; if (DEBUG_INSTALL && isSystemPkgUpdated) { Loading Loading @@ -4048,6 +4048,23 @@ final class InstallPackageHelper { // equal to the version on the /data partition. Throw an exception and use // the application already installed on the /data partition. if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) { // For some updated system packages, during addForInit we want to ensure the // PackageSetting has the correct SigningDetails compares to the original version on // the system partition. For the check to happen later during the /data scan, update // the disabled package setting per the original APK on a system partition so that it // can be trusted during reconcile. if (needSignatureMatchToSystem(parsedPackage.getPackageName())) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(input, parsedPackage, false /*skipVerify*/); if (result.isError()) { throw new PrepareFailure("Failed collect during scanSystemPackageLI", result.getException()); } disabledPkgSetting.setSigningDetails(result.getResult()); } // In the case of a skipped package, commitReconciledScanResultLocked is not called to // add the object to the "live" data structures, so this is the final mutation step // for the package. Which means it needs to be finalized here to cache derived fields. Loading @@ -4065,19 +4082,16 @@ final class InstallPackageHelper { // Verify certificates against what was last scanned. Force re-collecting certificate in two // special cases: // 1) when scanning system, force re-collect only if system is upgrading. // 2) when scanning /data, force re-collect only if the app is privileged (updated from // preinstall, or treated as privileged, e.g. due to shared user ID). // 2) when scanning /data, force re-collect only if the package name is allowlisted. final boolean forceCollect = scanSystemPartition ? isUpgrade : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting); : pkgAlreadyExists && needSignatureMatchToSystem(pkgSetting.getPackageName()); if (DEBUG_VERIFY && forceCollect) { Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // Full APK verification can be skipped during certificate collection, only if the file is // in verified partition, or can be verified on access (when apk verity is enabled). In both // cases, only data in Signing Block is verified instead of the whole file. final boolean skipVerify = scanSystemPartition || (forceCollect && canSkipForcedPackageVerification(parsedPackage)); // APK verification can be skipped during certificate collection, only if the file is in a // verified partition. final boolean skipVerify = scanSystemPartition; ScanPackageUtils.collectCertificatesLI(pkgSetting, parsedPackage, mPm.getSettingsVersionForPackage(parsedPackage), forceCollect, skipVerify, mPm.isPreNMR1Upgrade()); Loading Loading @@ -4196,22 +4210,15 @@ final class InstallPackageHelper { } /** * Returns if forced apk verification can be skipped for the whole package, including splits. * Returns whether the package needs a signature verification against the pre-installed version * at boot. */ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { if (!VerityUtils.hasFsverity(pkg.getBaseApkPath())) { return false; } // TODO: Allow base and splits to be verified individually. String[] splitCodePaths = pkg.getSplitCodePaths(); if (!ArrayUtils.isEmpty(splitCodePaths)) { for (int i = 0; i < splitCodePaths.length; i++) { if (!VerityUtils.hasFsverity(splitCodePaths[i])) { private boolean needSignatureMatchToSystem(String packageName) { if (!android.security.Flags.extendVbChainToUpdatedApk()) { return false; } } } return true; return mPm.mInjector.getSystemConfig().getPreinstallPackagesWithStrictSignatureCheck() .contains(packageName); } /** Loading services/core/java/com/android/server/pm/InstallRequest.java +2 −2 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; Loading Loading @@ -190,7 +189,7 @@ final class InstallRequest { // addForInit InstallRequest(ParsedPackage parsedPackage, int parseFlags, int scanFlags, @Nullable UserHandle user, ScanResult scanResult) { @Nullable UserHandle user, ScanResult scanResult, PackageSetting disabledPs) { if (user != null) { mUserId = user.getIdentifier(); } else { Loading @@ -206,6 +205,7 @@ final class InstallRequest { mPackageMetrics = null; // No logging from this code path mSessionId = -1; mRequireUserAction = USER_ACTION_UNSPECIFIED; mDisabledPs = disabledPs; } @Nullable Loading Loading
data/etc/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,12 @@ prebuilt_etc { src: "preinstalled-packages-asl-files.xml", } prebuilt_etc { name: "preinstalled-packages-strict-signature.xml", sub_dir: "sysconfig", src: "preinstalled-packages-strict-signature.xml", } // Privapp permission whitelist files prebuilt_etc { Loading
data/etc/preinstalled-packages-strict-signature.xml 0 → 100644 +27 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 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 file declares which preinstalled apps, after updated, need to have strict signature check in boot time and avoid the cached results. This is to ensure the updated version still verifies against the preinstalled version. Example usage: <require-strict-signature package="com.foo.bar"/> --> <config></config>
services/core/java/com/android/server/SystemConfig.java +19 −0 Original line number Diff line number Diff line Loading @@ -340,6 +340,10 @@ public class SystemConfig { // A map of preloaded package names and the path to its app metadata file path. private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>(); // A set of pre-installed package names that requires strict signature verification once // updated to avoid cached/potentially tampered results. private final Set<String> mPreinstallPackagesWithStrictSignatureCheck = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, * value maps actor name to package name. Loading Loading @@ -542,6 +546,10 @@ public class SystemConfig { return mAppMetadataFilePaths; } public Set<String> getPreinstallPackagesWithStrictSignatureCheck() { return mPreinstallPackagesWithStrictSignatureCheck; } /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. Loading Loading @@ -1485,6 +1493,17 @@ public class SystemConfig { mAppMetadataFilePaths.put(packageName, path); } } break; case "require-strict-signature": { if (android.security.Flags.extendVbChainToUpdatedApk()) { String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { Slog.w(TAG, "<" + name + "> without valid package in " + permFile + " at " + parser.getPositionDescription()); } else { mPreinstallPackagesWithStrictSignatureCheck.add(packageName); } } } break; default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); Loading
services/core/java/com/android/server/pm/InstallPackageHelper.java +31 −24 Original line number Diff line number Diff line Loading @@ -3728,7 +3728,7 @@ final class InstallPackageHelper { final ScanResult scanResult = scanResultPair.first; boolean shouldHideSystemApp = scanResultPair.second; final InstallRequest installRequest = new InstallRequest( parsedPackage, parseFlags, scanFlags, user, scanResult); parsedPackage, parseFlags, scanFlags, user, scanResult, disabledPkgSetting); String existingApexModuleName = null; synchronized (mPm.mLock) { Loading Loading @@ -3962,6 +3962,7 @@ final class InstallPackageHelper { final String disabledPkgName = pkgAlreadyExists ? pkgSetting.getPackageName() : parsedPackage.getPackageName(); final boolean isSystemPkgUpdated; final PackageSetting disabledPkgSetting; final boolean isUpgrade; synchronized (mPm.mLock) { isUpgrade = mPm.isDeviceUpgrading(); Loading @@ -3975,8 +3976,7 @@ final class InstallPackageHelper { + "and install it as non-updated system app."); mPm.mSettings.removeDisabledSystemPackageLPw(disabledPkgName); } final PackageSetting disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName); disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName); isSystemPkgUpdated = disabledPkgSetting != null; if (DEBUG_INSTALL && isSystemPkgUpdated) { Loading Loading @@ -4048,6 +4048,23 @@ final class InstallPackageHelper { // equal to the version on the /data partition. Throw an exception and use // the application already installed on the /data partition. if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) { // For some updated system packages, during addForInit we want to ensure the // PackageSetting has the correct SigningDetails compares to the original version on // the system partition. For the check to happen later during the /data scan, update // the disabled package setting per the original APK on a system partition so that it // can be trusted during reconcile. if (needSignatureMatchToSystem(parsedPackage.getPackageName())) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(input, parsedPackage, false /*skipVerify*/); if (result.isError()) { throw new PrepareFailure("Failed collect during scanSystemPackageLI", result.getException()); } disabledPkgSetting.setSigningDetails(result.getResult()); } // In the case of a skipped package, commitReconciledScanResultLocked is not called to // add the object to the "live" data structures, so this is the final mutation step // for the package. Which means it needs to be finalized here to cache derived fields. Loading @@ -4065,19 +4082,16 @@ final class InstallPackageHelper { // Verify certificates against what was last scanned. Force re-collecting certificate in two // special cases: // 1) when scanning system, force re-collect only if system is upgrading. // 2) when scanning /data, force re-collect only if the app is privileged (updated from // preinstall, or treated as privileged, e.g. due to shared user ID). // 2) when scanning /data, force re-collect only if the package name is allowlisted. final boolean forceCollect = scanSystemPartition ? isUpgrade : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting); : pkgAlreadyExists && needSignatureMatchToSystem(pkgSetting.getPackageName()); if (DEBUG_VERIFY && forceCollect) { Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // Full APK verification can be skipped during certificate collection, only if the file is // in verified partition, or can be verified on access (when apk verity is enabled). In both // cases, only data in Signing Block is verified instead of the whole file. final boolean skipVerify = scanSystemPartition || (forceCollect && canSkipForcedPackageVerification(parsedPackage)); // APK verification can be skipped during certificate collection, only if the file is in a // verified partition. final boolean skipVerify = scanSystemPartition; ScanPackageUtils.collectCertificatesLI(pkgSetting, parsedPackage, mPm.getSettingsVersionForPackage(parsedPackage), forceCollect, skipVerify, mPm.isPreNMR1Upgrade()); Loading Loading @@ -4196,22 +4210,15 @@ final class InstallPackageHelper { } /** * Returns if forced apk verification can be skipped for the whole package, including splits. * Returns whether the package needs a signature verification against the pre-installed version * at boot. */ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { if (!VerityUtils.hasFsverity(pkg.getBaseApkPath())) { return false; } // TODO: Allow base and splits to be verified individually. String[] splitCodePaths = pkg.getSplitCodePaths(); if (!ArrayUtils.isEmpty(splitCodePaths)) { for (int i = 0; i < splitCodePaths.length; i++) { if (!VerityUtils.hasFsverity(splitCodePaths[i])) { private boolean needSignatureMatchToSystem(String packageName) { if (!android.security.Flags.extendVbChainToUpdatedApk()) { return false; } } } return true; return mPm.mInjector.getSystemConfig().getPreinstallPackagesWithStrictSignatureCheck() .contains(packageName); } /** Loading
services/core/java/com/android/server/pm/InstallRequest.java +2 −2 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; Loading Loading @@ -190,7 +189,7 @@ final class InstallRequest { // addForInit InstallRequest(ParsedPackage parsedPackage, int parseFlags, int scanFlags, @Nullable UserHandle user, ScanResult scanResult) { @Nullable UserHandle user, ScanResult scanResult, PackageSetting disabledPs) { if (user != null) { mUserId = user.getIdentifier(); } else { Loading @@ -206,6 +205,7 @@ final class InstallRequest { mPackageMetrics = null; // No logging from this code path mSessionId = -1; mRequireUserAction = USER_ACTION_UNSPECIFIED; mDisabledPs = disabledPs; } @Nullable Loading