Loading services/core/java/com/android/server/pm/PackageManagerService.java +13 −7 Original line number Diff line number Diff line Loading @@ -8183,12 +8183,12 @@ public class PackageManagerService extends IPackageManager.Stub } private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, final @ParseFlags int parseFlags) throws PackageManagerException { final @ParseFlags int parseFlags, boolean forceCollect) throws PackageManagerException { // When upgrading from pre-N MR1, verify the package time stamp using the package // directory and not the APK file. final long lastModifiedTime = mIsPreNMR1Upgrade ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg); if (ps != null if (ps != null && !forceCollect && ps.codePathString.equals(pkg.codePath) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(pkg) Loading @@ -8211,7 +8211,8 @@ public class PackageManagerService extends IPackageManager.Stub Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them."); } else { Slog.i(TAG, toString() + " changed; collecting certs"); Slog.i(TAG, pkg.codePath + " changed; collecting certs" + (forceCollect ? " (forced)" : "")); } try { Loading Loading @@ -8452,8 +8453,11 @@ public class PackageManagerService extends IPackageManager.Stub + " better than this " + pkg.getLongVersionCode()); } // verify certificates against what was last scanned collectCertificatesLI(pkgSetting, pkg, parseFlags); // Verify certificates against what was last scanned. If it is an updated priv app, we will // force the verification. Full apk verification will happen unless apk verity is set up for // the file. In that case, only small part of the apk is verified upfront. collectCertificatesLI(pkgSetting, pkg, parseFlags, PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting)); boolean shouldHideSystemApp = false; // A new application appeared on /system, but, we already have a copy of Loading Loading @@ -9723,6 +9727,7 @@ public class PackageManagerService extends IPackageManager.Stub final @ScanFlags int scanFlags = request.scanFlags; final PackageSetting oldPkgSetting = request.oldPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; final PackageSetting disabledPkgSetting = request.disabledPkgSetting; final UserHandle user = request.user; final String realPkgName = request.realPkgName; final PackageSetting pkgSetting = result.pkgSetting; Loading Loading @@ -9805,7 +9810,7 @@ public class PackageManagerService extends IPackageManager.Stub try { final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); final boolean compatMatch = verifySignatures(signatureCheckPs, final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { Loading Loading @@ -16575,8 +16580,9 @@ public class PackageManagerService extends IPackageManager.Stub try { final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); // We don't care about disabledPkgSetting on install for now. final boolean compatMatch = verifySignatures( signatureCheckPs, pkg.mSigningDetails, compareCompat, signatureCheckPs, null, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +43 −2 Original line number Diff line number Diff line Loading @@ -33,10 +33,12 @@ import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.PackageDexUsage; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppGlobals; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.os.Build; Loading @@ -45,6 +47,7 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.service.pm.PackageServiceDumpProto; import android.system.ErrnoException; Loading Loading @@ -546,14 +549,47 @@ public class PackageManagerServiceUtils { return false; } /** * Make sure the updated priv app is signed with the same key as the original APK file on the * /system partition. * * <p>The rationale is that {@code disabledPkg} is a PackageSetting backed by xml files in /data * and is not tamperproof. */ private static boolean matchSignatureInSystem(PackageSetting pkgSetting, PackageSetting disabledPkgSetting) { try { PackageParser.collectCertificates(disabledPkgSetting.pkg, PackageParser.PARSE_IS_SYSTEM_DIR); if (compareSignatures(pkgSetting.signatures.mSignatures, disabledPkgSetting.signatures.mSignatures) != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " + pkgSetting.name); return false; } } catch (PackageParserException e) { logCriticalInfo(Log.ERROR, "Failed to collect cert for " + pkgSetting.name + ": " + e.getMessage()); return false; } return true; } /** Returns true to force apk verification if the updated package (in /data) is a priv app. */ static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) { return disabledPs != null && disabledPs.isPrivileged() && SystemProperties.getInt("ro.apk_verity.mode", 0) != 0; } /** * Verifies that signatures match. * @returns {@code true} if the compat signatures were matched; otherwise, {@code false}. * @throws PackageManagerException if the signatures did not match. */ public static boolean verifySignatures(PackageSetting pkgSetting, PackageParser.SigningDetails parsedSignatures, boolean compareCompat, boolean compareRecover) PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures, boolean compareCompat, boolean compareRecover) throws PackageManagerException { final String packageName = pkgSetting.name; boolean compatMatch = false; Loading @@ -572,6 +608,11 @@ public class PackageManagerServiceUtils { packageName, pkgSetting.signatures.mSignatures, parsedSignatures.signatures); } if (!match && isApkVerificationForced(disabledPkgSetting)) { match = matchSignatureInSystem(pkgSetting, disabledPkgSetting); } if (!match) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + packageName + Loading Loading
services/core/java/com/android/server/pm/PackageManagerService.java +13 −7 Original line number Diff line number Diff line Loading @@ -8183,12 +8183,12 @@ public class PackageManagerService extends IPackageManager.Stub } private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, final @ParseFlags int parseFlags) throws PackageManagerException { final @ParseFlags int parseFlags, boolean forceCollect) throws PackageManagerException { // When upgrading from pre-N MR1, verify the package time stamp using the package // directory and not the APK file. final long lastModifiedTime = mIsPreNMR1Upgrade ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg); if (ps != null if (ps != null && !forceCollect && ps.codePathString.equals(pkg.codePath) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(pkg) Loading @@ -8211,7 +8211,8 @@ public class PackageManagerService extends IPackageManager.Stub Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them."); } else { Slog.i(TAG, toString() + " changed; collecting certs"); Slog.i(TAG, pkg.codePath + " changed; collecting certs" + (forceCollect ? " (forced)" : "")); } try { Loading Loading @@ -8452,8 +8453,11 @@ public class PackageManagerService extends IPackageManager.Stub + " better than this " + pkg.getLongVersionCode()); } // verify certificates against what was last scanned collectCertificatesLI(pkgSetting, pkg, parseFlags); // Verify certificates against what was last scanned. If it is an updated priv app, we will // force the verification. Full apk verification will happen unless apk verity is set up for // the file. In that case, only small part of the apk is verified upfront. collectCertificatesLI(pkgSetting, pkg, parseFlags, PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting)); boolean shouldHideSystemApp = false; // A new application appeared on /system, but, we already have a copy of Loading Loading @@ -9723,6 +9727,7 @@ public class PackageManagerService extends IPackageManager.Stub final @ScanFlags int scanFlags = request.scanFlags; final PackageSetting oldPkgSetting = request.oldPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; final PackageSetting disabledPkgSetting = request.disabledPkgSetting; final UserHandle user = request.user; final String realPkgName = request.realPkgName; final PackageSetting pkgSetting = result.pkgSetting; Loading Loading @@ -9805,7 +9810,7 @@ public class PackageManagerService extends IPackageManager.Stub try { final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); final boolean compatMatch = verifySignatures(signatureCheckPs, final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { Loading Loading @@ -16575,8 +16580,9 @@ public class PackageManagerService extends IPackageManager.Stub try { final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); // We don't care about disabledPkgSetting on install for now. final boolean compatMatch = verifySignatures( signatureCheckPs, pkg.mSigningDetails, compareCompat, signatureCheckPs, null, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) {
services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +43 −2 Original line number Diff line number Diff line Loading @@ -33,10 +33,12 @@ import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.PackageDexUsage; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppGlobals; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.os.Build; Loading @@ -45,6 +47,7 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.service.pm.PackageServiceDumpProto; import android.system.ErrnoException; Loading Loading @@ -546,14 +549,47 @@ public class PackageManagerServiceUtils { return false; } /** * Make sure the updated priv app is signed with the same key as the original APK file on the * /system partition. * * <p>The rationale is that {@code disabledPkg} is a PackageSetting backed by xml files in /data * and is not tamperproof. */ private static boolean matchSignatureInSystem(PackageSetting pkgSetting, PackageSetting disabledPkgSetting) { try { PackageParser.collectCertificates(disabledPkgSetting.pkg, PackageParser.PARSE_IS_SYSTEM_DIR); if (compareSignatures(pkgSetting.signatures.mSignatures, disabledPkgSetting.signatures.mSignatures) != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " + pkgSetting.name); return false; } } catch (PackageParserException e) { logCriticalInfo(Log.ERROR, "Failed to collect cert for " + pkgSetting.name + ": " + e.getMessage()); return false; } return true; } /** Returns true to force apk verification if the updated package (in /data) is a priv app. */ static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) { return disabledPs != null && disabledPs.isPrivileged() && SystemProperties.getInt("ro.apk_verity.mode", 0) != 0; } /** * Verifies that signatures match. * @returns {@code true} if the compat signatures were matched; otherwise, {@code false}. * @throws PackageManagerException if the signatures did not match. */ public static boolean verifySignatures(PackageSetting pkgSetting, PackageParser.SigningDetails parsedSignatures, boolean compareCompat, boolean compareRecover) PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures, boolean compareCompat, boolean compareRecover) throws PackageManagerException { final String packageName = pkgSetting.name; boolean compatMatch = false; Loading @@ -572,6 +608,11 @@ public class PackageManagerServiceUtils { packageName, pkgSetting.signatures.mSignatures, parsedSignatures.signatures); } if (!match && isApkVerificationForced(disabledPkgSetting)) { match = matchSignatureInSystem(pkgSetting, disabledPkgSetting); } if (!match) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + packageName + Loading