From 00e236eb6e87b8bae0dfcdca67bee67ccd5d014c Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Thu, 27 Feb 2025 17:25:22 -0800 Subject: Add install-time SDM signature verification. SDM is a new file format that contains the cloud compilation artifacts. As a requirement, the SDM file should be signed with the same key as the apk. This CL adds the SDM signature verification. If the verification fails, the package manager will fail the installation. Bug: 377474232 Change-Id: Ife6ee0fe10c9cee722705ef9f7497028e22036ff Test: Installed app signed with an incorrect key and verified that INSTALL_FAILED_INVALID_APK is thrown Flag: android.content.pm.cloud_compilation_verification --- .../android/server/pm/PackageInstallerSession.java | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 9edbaa8fadd9..2bf4b377bdd3 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_INSTA import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO; import static android.content.pm.DataLoaderType.INCREMENTAL; import static android.content.pm.DataLoaderType.STREAMING; +import static android.content.pm.Flags.cloudCompilationVerification; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; @@ -3570,6 +3571,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes()); } + if (cloudCompilationVerification()) { + verifySdmSignatures(artManagedFilePaths, mSigningDetails); + } + if (removeSplitList.size() > 0) { if (pkgInfo == null) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, @@ -3934,6 +3939,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { File targetArtManagedFile = new File( ArtManagedInstallFileHelper.getTargetPathForApk(path, targetFile.getPath())); stageFileLocked(artManagedFile, targetArtManagedFile); + if (!artManagedFile.equals(targetArtManagedFile)) { + // The file has been renamed. Update the list to reflect the change. + for (int i = 0; i < artManagedFilePaths.size(); ++i) { + if (artManagedFilePaths.get(i).equals(path)) { + artManagedFilePaths.set(i, targetArtManagedFile.getAbsolutePath()); + } + } + } } } @@ -4261,6 +4274,37 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return true; } + /** + * Verifies the signatures of SDM files. + * + * SDM is a file format that contains the cloud compilation artifacts. As a requirement, the SDM + * file should be signed with the same key as the APK. + * + * TODO(b/377474232): Move this logic to ART Service. + */ + private static void verifySdmSignatures(List artManagedFilePaths, + SigningDetails expectedSigningDetails) throws PackageManagerException { + ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + for (String path : artManagedFilePaths) { + if (!path.endsWith(".sdm")) { + continue; + } + // SDM is a format introduced in Android 16, so we don't need to support older + // signature schemes. + int minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3; + ParseResult verified = + ApkSignatureVerifier.verify(input, path, minSignatureScheme); + if (verified.isError()) { + throw new PackageManagerException( + INSTALL_FAILED_INVALID_APK, "Failed to verify SDM signatures"); + } + if (!expectedSigningDetails.signaturesMatchExactly(verified.getResult())) { + throw new PackageManagerException( + INSTALL_FAILED_INVALID_APK, "SDM signatures are inconsistent with APK"); + } + } + } + /** * @return the uid of the owner this session */ -- cgit v1.2.3-59-g8ed1b