Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 307f10a4 authored by Song Pan's avatar Song Pan Committed by Android (Google) Code Review
Browse files

Merge "Implement the InstallerAllowedByManifest rule."

parents 8d95abab 6a0fd8b0
Loading
Loading
Loading
Loading
+52 −6
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package android.content.integrity;

import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.Map;

/**
@@ -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() {
@@ -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) {
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -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);
        }
+20 −2
Original line number Diff line number Diff line
@@ -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
@@ -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"))
@@ -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()
+9 −9
Original line number Diff line number Diff line
@@ -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;

@@ -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";

@@ -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;
@@ -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: "
@@ -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);
                    }
                }
            }
+4 −47
Original line number Diff line number Diff line
@@ -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;

@@ -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.
@@ -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 {
@@ -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