summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java20
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java45
2 files changed, 56 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f7f78b9cfcfe..c75507a37687 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8193,12 +8193,12 @@ Slog.e("TODD",
}
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)
@@ -8221,7 +8221,8 @@ Slog.e("TODD",
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 {
@@ -8530,8 +8531,11 @@ Slog.e("TODD",
+ " 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
@@ -9835,6 +9839,7 @@ Slog.e("TODD",
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;
@@ -9917,7 +9922,7 @@ Slog.e("TODD",
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) {
@@ -16687,8 +16692,9 @@ Slog.e("TODD",
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) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index df836de21a80..7b96ca67d38f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -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;
@@ -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;
@@ -547,13 +550,46 @@ public class PackageManagerServiceUtils {
}
/**
+ * 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;
@@ -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 +