Loading core/java/android/content/integrity/InstallerAllowedByManifestFormula.java +52 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package android.content.integrity; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import java.util.Map; /** Loading @@ -25,7 +29,29 @@ import java.util.Map; * * @hide */ public class InstallerAllowedByManifestFormula extends IntegrityFormula { public class InstallerAllowedByManifestFormula extends IntegrityFormula implements Parcelable { public static final String INSTALLER_CERTIFICATE_NOT_EVALUATED = ""; public InstallerAllowedByManifestFormula() { } private InstallerAllowedByManifestFormula(Parcel in) { } @NonNull public static final Creator<InstallerAllowedByManifestFormula> CREATOR = new Creator<InstallerAllowedByManifestFormula>() { @Override public InstallerAllowedByManifestFormula createFromParcel(Parcel in) { return new InstallerAllowedByManifestFormula(in); } @Override public InstallerAllowedByManifestFormula[] newArray(int size) { return new InstallerAllowedByManifestFormula[size]; } }; @Override public int getTag() { Loading Loading @@ -54,10 +80,30 @@ public class InstallerAllowedByManifestFormula extends IntegrityFormula { private static boolean installerInAllowedInstallersFromManifest( AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallersAndCertificates) { return allowedInstallersAndCertificates.containsKey(appInstallMetadata.getInstallerName()) && appInstallMetadata.getInstallerCertificates() String installerPackage = appInstallMetadata.getInstallerName(); if (!allowedInstallersAndCertificates.containsKey(installerPackage)) { return false; } // If certificate is not specified in the manifest, we do not check it. if (!allowedInstallersAndCertificates.get(installerPackage) .equals(INSTALLER_CERTIFICATE_NOT_EVALUATED)) { return appInstallMetadata.getInstallerCertificates() .contains( allowedInstallersAndCertificates .get(appInstallMetadata.getInstallerName())); } return true; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { } } core/java/android/content/integrity/IntegrityFormula.java +2 −0 Original line number Diff line number Diff line Loading @@ -214,6 +214,8 @@ public abstract class IntegrityFormula { return LongAtomicFormula.CREATOR.createFromParcel(in); case BOOLEAN_ATOMIC_FORMULA_TAG: return BooleanAtomicFormula.CREATOR.createFromParcel(in); case INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG: return InstallerAllowedByManifestFormula.CREATOR.createFromParcel(in); default: throw new IllegalArgumentException("Unknown formula tag " + tag); } Loading core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java +20 −2 Original line number Diff line number Diff line Loading @@ -16,15 +16,20 @@ package android.content.integrity; import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED; import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableMap; import org.testng.annotations.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.Arrays; import java.util.Collections; @RunWith(JUnit4.class) public class InstallerAllowedByManifestFormulaTest { private static final InstallerAllowedByManifestFormula Loading Loading @@ -70,7 +75,7 @@ public class InstallerAllowedByManifestFormulaTest { } @Test public void testFormulaMatches_certificateNotInManifest() { public void testFormulaMatches_certificateDoesNotMatchManifest() { AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder() .setInstallerName("installer1") .setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert")) Loading @@ -92,6 +97,19 @@ public class InstallerAllowedByManifestFormulaTest { assertThat(FORMULA.matches(appInstallMetadata)).isTrue(); } @Test public void testFormulaMatches_certificateNotSpecifiedInManifest() { AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder() .setInstallerName("installer1") .setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert")) .setAllowedInstallersAndCert(ImmutableMap.of( "installer1", INSTALLER_CERTIFICATE_NOT_EVALUATED, "installer2", "installer_cert1" )).build(); assertThat(FORMULA.matches(appInstallMetadata)).isTrue(); } /** Returns a builder with all fields filled with some dummy data. */ private AppInstallMetadata.Builder getAppInstallMetadataBuilder() { return new AppInstallMetadata.Builder() Loading services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +9 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS; import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE; import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS; import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED; import static android.content.integrity.IntegrityUtils.getHexDigest; import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; Loading Loading @@ -95,7 +96,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { * This string will be used as the "installer" for formula evaluation when the app is being * installed via ADB. */ private static final String ADB_INSTALLER = "adb"; public static final String ADB_INSTALLER = "adb"; private static final String TAG = "AppIntegrityManagerServiceImpl"; Loading @@ -106,8 +107,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private static final String ALLOWED_INSTALLER_DELIMITER = ","; private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|"; private static final String INSTALLER_CERT_NOT_APPLICABLE = ""; // Access to files inside mRulesDir is protected by mRulesLock; private final Context mContext; private final Handler mHandler; Loading Loading @@ -282,15 +281,16 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { builder.setInstallerName(getPackageNameNormalized(installerPackageName)); builder.setInstallerCertificates(installerCertificates); builder.setIsPreInstalled(isSystemApp(packageName)); builder.setAllowedInstallersAndCert(getAllowedInstallers(packageInfo)); AppInstallMetadata appInstallMetadata = builder.build(); Map<String, String> allowedInstallers = getAllowedInstallers(packageInfo); Slog.i( TAG, "To be verified: " + appInstallMetadata + " installers " + allowedInstallers); "To be verified: " + appInstallMetadata + " installers " + getAllowedInstallers( packageInfo)); IntegrityCheckResult result = mEvaluationEngine.evaluate(appInstallMetadata, allowedInstallers); mEvaluationEngine.evaluate(appInstallMetadata); Slog.i( TAG, "Integrity check result: " Loading Loading @@ -449,9 +449,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { String packageName = getPackageNameNormalized(packageAndCert[0]); String cert = packageAndCert[1]; packageCertMap.put(packageName, cert); } else if (packageAndCert.length == 1 && packageAndCert[0].equals(ADB_INSTALLER)) { packageCertMap.put(ADB_INSTALLER, INSTALLER_CERT_NOT_APPLICABLE); } else if (packageAndCert.length == 1) { packageCertMap.put(getPackageNameNormalized(packageAndCert[0]), INSTALLER_CERTIFICATE_NOT_EVALUATED); } } } Loading services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java +4 −47 Original line number Diff line number Diff line Loading @@ -17,9 +17,6 @@ package com.android.server.integrity.engine; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Slog; Loading @@ -28,10 +25,8 @@ import com.android.server.integrity.IntegrityFileManager; import com.android.server.integrity.model.IntegrityCheckResult; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; /** * The engine used to evaluate rules against app installs. Loading Loading @@ -69,16 +64,15 @@ public class RuleEvaluationEngine { * @return result of the integrity check */ public IntegrityCheckResult evaluate( AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallers) { AppInstallMetadata appInstallMetadata) { List<Rule> rules = loadRules(appInstallMetadata); allowedInstallersRule(allowedInstallers).ifPresent(rules::add); return RuleEvaluator.evaluateRules(rules, appInstallMetadata); } private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) { if (!mIntegrityFileManager.initialized()) { Slog.w(TAG, "Integrity rule files are not available. Evaluating only manifest rules."); return new ArrayList<>(); Slog.w(TAG, "Integrity rule files are not available."); return Collections.emptyList(); } try { Loading @@ -88,41 +82,4 @@ public class RuleEvaluationEngine { return new ArrayList<>(); } } private static Optional<Rule> allowedInstallersRule(Map<String, String> allowedInstallers) { if (allowedInstallers.isEmpty()) { return Optional.empty(); } List<IntegrityFormula> formulas = new ArrayList<>(allowedInstallers.size()); allowedInstallers.forEach( (installer, cert) -> { formulas.add(allowedInstallerFormula(installer, cert)); }); // We need this special case since OR-formulas require at least two operands. IntegrityFormula allInstallersFormula = formulas.size() == 1 ? formulas.get(0) : new CompoundFormula(CompoundFormula.OR, formulas); return Optional.of( new Rule( new CompoundFormula( CompoundFormula.NOT, Arrays.asList(allInstallersFormula)), Rule.DENY)); } private static IntegrityFormula allowedInstallerFormula(String installer, String cert) { return new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_NAME, installer, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_CERTIFICATE, cert, /* isHashedValue= */ false))); } } Loading
core/java/android/content/integrity/InstallerAllowedByManifestFormula.java +52 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package android.content.integrity; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import java.util.Map; /** Loading @@ -25,7 +29,29 @@ import java.util.Map; * * @hide */ public class InstallerAllowedByManifestFormula extends IntegrityFormula { public class InstallerAllowedByManifestFormula extends IntegrityFormula implements Parcelable { public static final String INSTALLER_CERTIFICATE_NOT_EVALUATED = ""; public InstallerAllowedByManifestFormula() { } private InstallerAllowedByManifestFormula(Parcel in) { } @NonNull public static final Creator<InstallerAllowedByManifestFormula> CREATOR = new Creator<InstallerAllowedByManifestFormula>() { @Override public InstallerAllowedByManifestFormula createFromParcel(Parcel in) { return new InstallerAllowedByManifestFormula(in); } @Override public InstallerAllowedByManifestFormula[] newArray(int size) { return new InstallerAllowedByManifestFormula[size]; } }; @Override public int getTag() { Loading Loading @@ -54,10 +80,30 @@ public class InstallerAllowedByManifestFormula extends IntegrityFormula { private static boolean installerInAllowedInstallersFromManifest( AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallersAndCertificates) { return allowedInstallersAndCertificates.containsKey(appInstallMetadata.getInstallerName()) && appInstallMetadata.getInstallerCertificates() String installerPackage = appInstallMetadata.getInstallerName(); if (!allowedInstallersAndCertificates.containsKey(installerPackage)) { return false; } // If certificate is not specified in the manifest, we do not check it. if (!allowedInstallersAndCertificates.get(installerPackage) .equals(INSTALLER_CERTIFICATE_NOT_EVALUATED)) { return appInstallMetadata.getInstallerCertificates() .contains( allowedInstallersAndCertificates .get(appInstallMetadata.getInstallerName())); } return true; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { } }
core/java/android/content/integrity/IntegrityFormula.java +2 −0 Original line number Diff line number Diff line Loading @@ -214,6 +214,8 @@ public abstract class IntegrityFormula { return LongAtomicFormula.CREATOR.createFromParcel(in); case BOOLEAN_ATOMIC_FORMULA_TAG: return BooleanAtomicFormula.CREATOR.createFromParcel(in); case INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG: return InstallerAllowedByManifestFormula.CREATOR.createFromParcel(in); default: throw new IllegalArgumentException("Unknown formula tag " + tag); } Loading
core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java +20 −2 Original line number Diff line number Diff line Loading @@ -16,15 +16,20 @@ package android.content.integrity; import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED; import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableMap; import org.testng.annotations.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.Arrays; import java.util.Collections; @RunWith(JUnit4.class) public class InstallerAllowedByManifestFormulaTest { private static final InstallerAllowedByManifestFormula Loading Loading @@ -70,7 +75,7 @@ public class InstallerAllowedByManifestFormulaTest { } @Test public void testFormulaMatches_certificateNotInManifest() { public void testFormulaMatches_certificateDoesNotMatchManifest() { AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder() .setInstallerName("installer1") .setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert")) Loading @@ -92,6 +97,19 @@ public class InstallerAllowedByManifestFormulaTest { assertThat(FORMULA.matches(appInstallMetadata)).isTrue(); } @Test public void testFormulaMatches_certificateNotSpecifiedInManifest() { AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder() .setInstallerName("installer1") .setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert")) .setAllowedInstallersAndCert(ImmutableMap.of( "installer1", INSTALLER_CERTIFICATE_NOT_EVALUATED, "installer2", "installer_cert1" )).build(); assertThat(FORMULA.matches(appInstallMetadata)).isTrue(); } /** Returns a builder with all fields filled with some dummy data. */ private AppInstallMetadata.Builder getAppInstallMetadataBuilder() { return new AppInstallMetadata.Builder() Loading
services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +9 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS; import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE; import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS; import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED; import static android.content.integrity.IntegrityUtils.getHexDigest; import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; Loading Loading @@ -95,7 +96,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { * This string will be used as the "installer" for formula evaluation when the app is being * installed via ADB. */ private static final String ADB_INSTALLER = "adb"; public static final String ADB_INSTALLER = "adb"; private static final String TAG = "AppIntegrityManagerServiceImpl"; Loading @@ -106,8 +107,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private static final String ALLOWED_INSTALLER_DELIMITER = ","; private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|"; private static final String INSTALLER_CERT_NOT_APPLICABLE = ""; // Access to files inside mRulesDir is protected by mRulesLock; private final Context mContext; private final Handler mHandler; Loading Loading @@ -282,15 +281,16 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { builder.setInstallerName(getPackageNameNormalized(installerPackageName)); builder.setInstallerCertificates(installerCertificates); builder.setIsPreInstalled(isSystemApp(packageName)); builder.setAllowedInstallersAndCert(getAllowedInstallers(packageInfo)); AppInstallMetadata appInstallMetadata = builder.build(); Map<String, String> allowedInstallers = getAllowedInstallers(packageInfo); Slog.i( TAG, "To be verified: " + appInstallMetadata + " installers " + allowedInstallers); "To be verified: " + appInstallMetadata + " installers " + getAllowedInstallers( packageInfo)); IntegrityCheckResult result = mEvaluationEngine.evaluate(appInstallMetadata, allowedInstallers); mEvaluationEngine.evaluate(appInstallMetadata); Slog.i( TAG, "Integrity check result: " Loading Loading @@ -449,9 +449,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { String packageName = getPackageNameNormalized(packageAndCert[0]); String cert = packageAndCert[1]; packageCertMap.put(packageName, cert); } else if (packageAndCert.length == 1 && packageAndCert[0].equals(ADB_INSTALLER)) { packageCertMap.put(ADB_INSTALLER, INSTALLER_CERT_NOT_APPLICABLE); } else if (packageAndCert.length == 1) { packageCertMap.put(getPackageNameNormalized(packageAndCert[0]), INSTALLER_CERTIFICATE_NOT_EVALUATED); } } } Loading
services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java +4 −47 Original line number Diff line number Diff line Loading @@ -17,9 +17,6 @@ package com.android.server.integrity.engine; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Slog; Loading @@ -28,10 +25,8 @@ import com.android.server.integrity.IntegrityFileManager; import com.android.server.integrity.model.IntegrityCheckResult; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; /** * The engine used to evaluate rules against app installs. Loading Loading @@ -69,16 +64,15 @@ public class RuleEvaluationEngine { * @return result of the integrity check */ public IntegrityCheckResult evaluate( AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallers) { AppInstallMetadata appInstallMetadata) { List<Rule> rules = loadRules(appInstallMetadata); allowedInstallersRule(allowedInstallers).ifPresent(rules::add); return RuleEvaluator.evaluateRules(rules, appInstallMetadata); } private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) { if (!mIntegrityFileManager.initialized()) { Slog.w(TAG, "Integrity rule files are not available. Evaluating only manifest rules."); return new ArrayList<>(); Slog.w(TAG, "Integrity rule files are not available."); return Collections.emptyList(); } try { Loading @@ -88,41 +82,4 @@ public class RuleEvaluationEngine { return new ArrayList<>(); } } private static Optional<Rule> allowedInstallersRule(Map<String, String> allowedInstallers) { if (allowedInstallers.isEmpty()) { return Optional.empty(); } List<IntegrityFormula> formulas = new ArrayList<>(allowedInstallers.size()); allowedInstallers.forEach( (installer, cert) -> { formulas.add(allowedInstallerFormula(installer, cert)); }); // We need this special case since OR-formulas require at least two operands. IntegrityFormula allInstallersFormula = formulas.size() == 1 ? formulas.get(0) : new CompoundFormula(CompoundFormula.OR, formulas); return Optional.of( new Rule( new CompoundFormula( CompoundFormula.NOT, Arrays.asList(allInstallersFormula)), Rule.DENY)); } private static IntegrityFormula allowedInstallerFormula(String installer, String cert) { return new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_NAME, installer, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_CERTIFICATE, cert, /* isHashedValue= */ false))); } }