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

Commit 6a0fd8b0 authored by Song Pan's avatar Song Pan
Browse files

Implement the InstallerAllowedByManifest rule.

Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/integrity
Test: atest frameworks/base/core/tests/coretests/src/android/content/integrity
Bug: 148780440
Change-Id: Ie452e2a8a93b31ee91ae6d3e119212684c022c6a
parent 4bfcfe79
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