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

Commit 477d06b6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Remove the RuleEvaluator for AppIntegrityManager. This is part of the...

Merge "Remove the RuleEvaluator for AppIntegrityManager. This is part of the efforts for cleaning the install-time integrity protections." into main am: 918b5587 am: 86d1ddc8

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3304817



Change-Id: I94b3f099e3c2837d88a2cab68afbcd52c091f0fa
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 22d985de 86d1ddc8
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -66,7 +66,7 @@ public class RuleEvaluationEngine {
    public IntegrityCheckResult evaluate(
    public IntegrityCheckResult evaluate(
            AppInstallMetadata appInstallMetadata) {
            AppInstallMetadata appInstallMetadata) {
        List<Rule> rules = loadRules(appInstallMetadata);
        List<Rule> rules = loadRules(appInstallMetadata);
        return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
        return IntegrityCheckResult.allow();
    }
    }


    private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
    private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
+0 −81
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.integrity.engine;

import static android.content.integrity.Rule.DENY;
import static android.content.integrity.Rule.FORCE_ALLOW;

import android.annotation.NonNull;
import android.content.integrity.AppInstallMetadata;
import android.content.integrity.Rule;

import com.android.server.integrity.model.IntegrityCheckResult;

import java.util.List;
import java.util.stream.Collectors;

/**
 * A helper class for evaluating rules against app install metadata to find if there are matching
 * rules.
 */
final class RuleEvaluator {

    /**
     * Match the list of rules against an app install metadata.
     *
     * <p>Rules must be in disjunctive normal form (DNF). A rule should contain AND'ed formulas
     * only. All rules are OR'ed together by default.
     *
     * @param rules The list of rules to evaluate.
     * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
     *     against.
     * @return result of the integrity check
     */
    @NonNull
    static IntegrityCheckResult evaluateRules(
            List<Rule> rules, AppInstallMetadata appInstallMetadata) {

        // Identify the rules that match the {@code appInstallMetadata}.
        List<Rule> matchedRules =
                rules.stream()
                        .filter(rule -> rule.getFormula().matches(appInstallMetadata))
                        .collect(Collectors.toList());

        // Identify the matched power allow rules and terminate early if we have any.
        List<Rule> matchedPowerAllowRules =
                matchedRules.stream()
                        .filter(rule -> rule.getEffect() == FORCE_ALLOW)
                        .collect(Collectors.toList());

        if (!matchedPowerAllowRules.isEmpty()) {
            return IntegrityCheckResult.allow(matchedPowerAllowRules);
        }

        // Identify the matched deny rules.
        List<Rule> matchedDenyRules =
                matchedRules.stream()
                        .filter(rule -> rule.getEffect() == DENY)
                        .collect(Collectors.toList());

        if (!matchedDenyRules.isEmpty()) {
            return IntegrityCheckResult.deny(matchedDenyRules);
        }

        // When no rules are denied, return default allow result.
        return IntegrityCheckResult.allow();
    }
}
+5 −5
Original line number Original line Diff line number Diff line
@@ -114,7 +114,7 @@ public class RuleEvaluationEngineTest {
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .build();
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.DENY);
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);


        AppInstallMetadata appInstallMetadata3 =
        AppInstallMetadata appInstallMetadata3 =
                getAppInstallMetadataBuilder()
                getAppInstallMetadataBuilder()
@@ -123,7 +123,7 @@ public class RuleEvaluationEngineTest {
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .build();
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.DENY);
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);


        AppInstallMetadata appInstallMetadata4 =
        AppInstallMetadata appInstallMetadata4 =
                getAppInstallMetadataBuilder()
                getAppInstallMetadataBuilder()
@@ -132,7 +132,7 @@ public class RuleEvaluationEngineTest {
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .build();
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.DENY);
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
    }
    }


    @Test
    @Test
@@ -166,7 +166,7 @@ public class RuleEvaluationEngineTest {
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                        .build();
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.DENY);
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);


        AppInstallMetadata appInstallMetadata4 =
        AppInstallMetadata appInstallMetadata4 =
                getAppInstallMetadataBuilder()
                getAppInstallMetadataBuilder()
@@ -175,7 +175,7 @@ public class RuleEvaluationEngineTest {
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .build();
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.DENY);
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
    }
    }


    /** Returns a builder with all fields filled with some placeholder data. */
    /** Returns a builder with all fields filled with some placeholder data. */
+0 −299
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.integrity.engine;

import static com.android.server.integrity.model.IntegrityCheckResult.Effect.ALLOW;
import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DENY;

import static com.google.common.truth.Truth.assertThat;

import android.content.integrity.AppInstallMetadata;
import android.content.integrity.AtomicFormula;
import android.content.integrity.AtomicFormula.LongAtomicFormula;
import android.content.integrity.AtomicFormula.StringAtomicFormula;
import android.content.integrity.CompoundFormula;
import android.content.integrity.Rule;

import com.android.server.integrity.model.IntegrityCheckResult;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@RunWith(JUnit4.class)
public class RuleEvaluatorTest {

    private static final String PACKAGE_NAME_1 = "com.test.app";
    private static final String PACKAGE_NAME_2 = "com.test.app2";
    private static final String APP_CERTIFICATE = "test_cert";
    private static final AppInstallMetadata APP_INSTALL_METADATA =
            new AppInstallMetadata.Builder()
                    .setPackageName(PACKAGE_NAME_1)
                    .setAppCertificates(Collections.singletonList(APP_CERTIFICATE))
                    .setAppCertificateLineage(Collections.singletonList(APP_CERTIFICATE))
                    .setVersionCode(2)
                    .build();

    @Test
    public void testEvaluateRules_noRules_allow() {
        List<Rule> rules = new ArrayList<>();

        IntegrityCheckResult result = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(ALLOW);
    }

    @Test
    public void testEvaluateRules_noMatchedRules_allow() {
        Rule rule =
                new Rule(
                        new StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                PACKAGE_NAME_2,
                                /* isHashedValue= */ false),
                        Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(ALLOW);
    }

    @Test
    public void testEvaluateRules_oneMatch_deny() {
        Rule rule1 =
                new Rule(
                        new StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                PACKAGE_NAME_1,
                                /* isHashedValue= */ false),
                        Rule.DENY);
        Rule rule2 =
                new Rule(
                        new StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                PACKAGE_NAME_2,
                                /* isHashedValue= */ false),
                        Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule1);
    }

    @Test
    public void testEvaluateRules_multipleMatches_deny() {
        Rule rule1 =
                new Rule(
                        new StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                PACKAGE_NAME_1,
                                /* isHashedValue= */ false),
                        Rule.DENY);
        Rule rule2 = new Rule(
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_1,
                                        /* isHashedValue= */ false),
                                new StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        APP_CERTIFICATE,
                                        /* isHashedValue= */ false))),
                Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule1, rule2);
    }

    @Test
    public void testEvaluateRules_ruleWithNot_deny() {
        Rule rule = new Rule(
                new CompoundFormula(
                        CompoundFormula.NOT,
                        Collections.singletonList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_2,
                                        /* isHashedValue= */ false))),
                Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule);
    }

    @Test
    public void testEvaluateRules_ruleWithIntegerOperators_deny() {
        Rule rule =
                new Rule(
                        new LongAtomicFormula(AtomicFormula.VERSION_CODE,
                                AtomicFormula.GT, 1),
                        Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule);
    }

    @Test
    public void testEvaluateRules_validForm_deny() {
        Rule rule = new Rule(
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_1,
                                        /* isHashedValue= */ false),
                                new StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        APP_CERTIFICATE,
                                        /* isHashedValue= */ false))),
                Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule);
    }

    @Test
    public void testEvaluateRules_orRules() {
        Rule rule = new Rule(
                new CompoundFormula(
                        CompoundFormula.OR,
                        Arrays.asList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_1,
                                        /* isHashedValue= */ false),
                                new StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        APP_CERTIFICATE,
                                        /* isHashedValue= */ false))),
                Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule);
    }

    @Test
    public void testEvaluateRules_compoundFormulaWithNot_deny() {
        CompoundFormula openSubFormula =
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_2,
                                        /* isHashedValue= */ false),
                                new StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        APP_CERTIFICATE,
                                        /* isHashedValue= */ false)));
        CompoundFormula compoundFormula =
                new CompoundFormula(CompoundFormula.NOT, Collections.singletonList(openSubFormula));
        Rule rule = new Rule(compoundFormula, Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(DENY);
        assertThat(result.getMatchedRules()).containsExactly(rule);
    }

    @Test
    public void testEvaluateRules_forceAllow() {
        Rule rule1 =
                new Rule(
                        new StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                PACKAGE_NAME_1,
                                /* isHashedValue= */ false),
                        Rule.FORCE_ALLOW);
        Rule rule2 = new Rule(
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_1,
                                        /* isHashedValue= */ false),
                                new StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        APP_CERTIFICATE,
                                        /* isHashedValue= */ false))),
                Rule.DENY);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(ALLOW);
        assertThat(result.getMatchedRules()).containsExactly(rule1);
    }

    @Test
    public void testEvaluateRules_multipleMatches_forceAllow() {
        Rule rule1 =
                new Rule(
                        new StringAtomicFormula(
                                AtomicFormula.PACKAGE_NAME,
                                PACKAGE_NAME_1,
                                /* isHashedValue= */ false),
                        Rule.FORCE_ALLOW);
        Rule rule2 = new Rule(
                new CompoundFormula(
                        CompoundFormula.AND,
                        Arrays.asList(
                                new StringAtomicFormula(
                                        AtomicFormula.PACKAGE_NAME,
                                        PACKAGE_NAME_1,
                                        /* isHashedValue= */ false),
                                new StringAtomicFormula(
                                        AtomicFormula.APP_CERTIFICATE,
                                        APP_CERTIFICATE,
                                        /* isHashedValue= */ false))),
                Rule.FORCE_ALLOW);

        IntegrityCheckResult result =
                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);

        assertThat(result.getEffect()).isEqualTo(ALLOW);
        assertThat(result.getMatchedRules()).containsExactly(rule1, rule2);
    }
}
 No newline at end of file