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

Commit 30749c8f authored by Omer Nebil Yaveroglu's avatar Omer Nebil Yaveroglu
Browse files

Extend integrity component indexing type identification to also return

the key value that the indexing will be done with.

Bug: 145488708
Test: atest FrameworksServicesTests:RuleIndexIdentifierTest
Change-Id: I8205c0d85b7034c981079572ae6f5110d114d39a
parent 532c02c7
Loading
Loading
Loading
Loading
+67 −0
Original line number 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.serializer;

import android.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/** Holds the indexing type and indexing key of a given formula. */
class RuleIndexingDetails {

    static final int NOT_INDEXED = 0;
    static final int PACKAGE_NAME_INDEXED = 1;
    static final int APP_CERTIFICATE_INDEXED = 2;

    /** Represents which indexed file the rule should be located. */
    @IntDef(
            value = {
                    NOT_INDEXED,
                    PACKAGE_NAME_INDEXED,
                    APP_CERTIFICATE_INDEXED
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface IndexType {
    }

    private @IndexType int mIndexType;
    private String mRuleKey;

    /** Constructor without a ruleKey for {@code NOT_INDEXED}. */
    RuleIndexingDetails(@IndexType int indexType) {
        this.mIndexType = indexType;
        this.mRuleKey = null;
    }

    /** Constructor with a ruleKey for indexed rules. */
    RuleIndexingDetails(@IndexType int indexType, String ruleKey) {
        this.mIndexType = indexType;
        this.mRuleKey = ruleKey;
    }

    /** Returns the indexing type for the rule. */
    @IndexType
    public int getIndexType() {
        return mIndexType;
    }

    /** Returns the identified rule key. */
    public String getRuleKey() {
        return mRuleKey;
    }
}
+127 −0
Original line number Diff line number Diff line
@@ -16,45 +16,30 @@

package com.android.server.integrity.serializer;

import android.annotation.IntDef;
import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;

import android.content.integrity.AtomicFormula;
import android.content.integrity.CompoundFormula;
import android.content.integrity.Formula;
import android.content.integrity.Rule;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/** A helper class for identifying the indexing type of a given rule. */
public class RuleIndexTypeIdentifier {
import java.util.Optional;

    static final int NOT_INDEXED = 0;
    static final int PACKAGE_NAME_INDEXED = 1;
    static final int APP_CERTIFICATE_INDEXED = 2;

    /** Represents which indexed file the rule should be located. */
    @IntDef(
            value = {
                    NOT_INDEXED,
                    PACKAGE_NAME_INDEXED,
                    APP_CERTIFICATE_INDEXED
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface IndexType {
    }
/** A helper class for identifying the indexing type and key of a given rule. */
class RuleIndexingDetailsIdentifier {

    /** Determines the indexing file type that a given rule should be located at. */
    public static int getIndexType(Rule rule) {
    /** Determines the indexing type and key for a given rule. */
    public static RuleIndexingDetails getIndexingDetails(Rule rule) {
        if (rule == null) {
            throw new IllegalArgumentException("Indexing type cannot be determined for null rule.");
        }
        return getIndexType(rule.getFormula());
        return getIndexingDetails(rule.getFormula());
    }

    private static int getIndexType(Formula formula) {
    private static RuleIndexingDetails getIndexingDetails(Formula formula) {
        if (formula == null) {
            throw new IllegalArgumentException(
                    "Indexing type cannot be determined for null formula.");
@@ -62,56 +47,81 @@ public class RuleIndexTypeIdentifier {

        switch (formula.getTag()) {
            case Formula.COMPOUND_FORMULA_TAG:
                return getIndexTypeForCompoundFormula((CompoundFormula) formula);
                return getIndexingDetailsForCompoundFormula((CompoundFormula) formula);
            case Formula.STRING_ATOMIC_FORMULA_TAG:
                return getIndexTypeForAtomicStringFormula((AtomicFormula) formula);
                return getIndexingDetailsForAtomicStringFormula((AtomicFormula) formula);
            case Formula.INT_ATOMIC_FORMULA_TAG:
            case Formula.BOOLEAN_ATOMIC_FORMULA_TAG:
                // Package name and app certificate related formulas are string atomic formulas.
                return NOT_INDEXED;
                return new RuleIndexingDetails(NOT_INDEXED);
            default:
                throw new IllegalArgumentException(
                        String.format("Invalid formula tag type: %s", formula.getTag()));
        }
    }

    private static int getIndexTypeForCompoundFormula(CompoundFormula compoundFormula) {
    private static RuleIndexingDetails getIndexingDetailsForCompoundFormula(
            CompoundFormula compoundFormula) {
        int connector = compoundFormula.getConnector();
        List<Formula> formulas = compoundFormula.getFormulas();

        switch (connector) {
            case CompoundFormula.NOT:
                // Having a NOT operator in the indexing messes up the indexing; e.g., deny
                // installation if app certificate is NOT X (should not be indexed with app cert
                // X). We will not keep these rules indexed.
                return NOT_INDEXED;
            case CompoundFormula.AND:
            case CompoundFormula.OR:
                Set<Integer> indexingTypesForAllFormulas =
                // If there is a package name related atomic rule, return package name indexed.
                Optional<RuleIndexingDetails> packageNameRule =
                        formulas.stream()
                                .map(formula -> getIndexingDetails(formula))
                                .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType()
                                        == PACKAGE_NAME_INDEXED)
                                .findAny();
                if (packageNameRule.isPresent()) {
                    return packageNameRule.get();
                }

                // If there is an app certificate related atomic rule but no package name related
                // atomic rule, return app certificate indexed.
                Optional<RuleIndexingDetails> appCertificateRule =
                        formulas.stream()
                                .map(formula -> getIndexType(formula))
                                .collect(Collectors.toSet());
                if (indexingTypesForAllFormulas.contains(PACKAGE_NAME_INDEXED)) {
                    return PACKAGE_NAME_INDEXED;
                } else if (indexingTypesForAllFormulas.contains(APP_CERTIFICATE_INDEXED)) {
                    return APP_CERTIFICATE_INDEXED;
                } else {
                    return NOT_INDEXED;
                                .map(formula -> getIndexingDetails(formula))
                                .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType()
                                        == APP_CERTIFICATE_INDEXED)
                                .findAny();
                if (appCertificateRule.isPresent()) {
                    return appCertificateRule.get();
                }

                // Do not index when there is not package name or app certificate indexing.
                return new RuleIndexingDetails(NOT_INDEXED);
            default:
                return NOT_INDEXED;
                // Having a NOT operator in the indexing messes up the indexing; e.g., deny
                // installation if app certificate is NOT X (should not be indexed with app cert
                // X). We will not keep these rules indexed.
                // Also any other type of unknown operators will not be indexed.
                return new RuleIndexingDetails(NOT_INDEXED);
        }
    }

    private static int getIndexTypeForAtomicStringFormula(AtomicFormula atomicFormula) {
    private static RuleIndexingDetails getIndexingDetailsForAtomicStringFormula(
            AtomicFormula atomicFormula) {
        switch (atomicFormula.getKey()) {
            case AtomicFormula.PACKAGE_NAME:
                return PACKAGE_NAME_INDEXED;
                return new RuleIndexingDetails(PACKAGE_NAME_INDEXED,
                        getValueFromAtomicRuleString(atomicFormula.toString()));
            case AtomicFormula.APP_CERTIFICATE:
                return APP_CERTIFICATE_INDEXED;
                return new RuleIndexingDetails(APP_CERTIFICATE_INDEXED,
                        getValueFromAtomicRuleString(atomicFormula.toString()));
            default:
                return NOT_INDEXED;
                return new RuleIndexingDetails(NOT_INDEXED);
        }
    }

    // The AtomRule API does not allow direct access to the {@link AtomicFormula} value. However,
    // this value is printed as "(%s %s %s)" where the last %s stands for the value. This method
    // parses the last.
    private static String getValueFromAtomicRuleString(String ruleString) {
        // TODO (b/145488708): Make an API change and get rid of this trick.
        return ruleString.split(" ")[2].split("[)]")[0];
    }
}
+22 −15
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.integrity.serializer;

import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
import static com.android.server.testutils.TestUtils.assertExpectException;

import static com.google.common.truth.Truth.assertThat;
@@ -34,9 +37,9 @@ import org.junit.runners.JUnit4;

import java.util.Arrays;

/** Unit tests for {@link RuleIndexTypeIdentifier}. */
/** Unit tests for {@link RuleIndexingDetailsIdentifier}. */
@RunWith(JUnit4.class)
public class RuleIndexTypeIdentifierTest {
public class RuleIndexingDetailsIdentifierTest {

    @Test
    public void getIndexType_nullRule() {
@@ -46,7 +49,7 @@ public class RuleIndexTypeIdentifierTest {
                IllegalArgumentException.class,
                /* expectedExceptionMessageRegex= */
                "Indexing type cannot be determined for null rule.",
                () -> RuleIndexTypeIdentifier.getIndexType(rule));
                () -> RuleIndexingDetailsIdentifier.getIndexingDetails(rule));
    }

    @Test
@@ -56,7 +59,7 @@ public class RuleIndexTypeIdentifierTest {
        assertExpectException(
                IllegalArgumentException.class,
                /* expectedExceptionMessageRegex= */ "Invalid formula tag type.",
                () -> RuleIndexTypeIdentifier.getIndexType(rule));
                () -> RuleIndexingDetailsIdentifier.getIndexingDetails(rule));
    }

    @Test
@@ -78,8 +81,10 @@ public class RuleIndexTypeIdentifierTest {
                                                /* isHashedValue= */ false))),
                        Rule.DENY);

        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
                .isEqualTo(RuleIndexTypeIdentifier.PACKAGE_NAME_INDEXED);
        RuleIndexingDetails result = RuleIndexingDetailsIdentifier.getIndexingDetails(rule);

        assertThat(result.getIndexType()).isEqualTo(PACKAGE_NAME_INDEXED);
        assertThat(result.getRuleKey()).isEqualTo(packageName);
    }

    @Test
@@ -101,8 +106,11 @@ public class RuleIndexTypeIdentifierTest {
                                                /* isHashedValue= */ false))),
                        Rule.DENY);

        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
                .isEqualTo(RuleIndexTypeIdentifier.APP_CERTIFICATE_INDEXED);

        RuleIndexingDetails result = RuleIndexingDetailsIdentifier.getIndexingDetails(rule);

        assertThat(result.getIndexType()).isEqualTo(APP_CERTIFICATE_INDEXED);
        assertThat(result.getRuleKey()).isEqualTo(appCertificate);
    }

    @Test
@@ -124,8 +132,8 @@ public class RuleIndexTypeIdentifierTest {
                                                /* isHashedValue= */ false))),
                        Rule.DENY);

        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
        assertThat(RuleIndexingDetailsIdentifier.getIndexingDetails(rule).getIndexType())
                .isEqualTo(NOT_INDEXED);
    }

    @Test
@@ -145,8 +153,8 @@ public class RuleIndexTypeIdentifierTest {
                                                appVersion))),
                        Rule.DENY);

        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
        assertThat(RuleIndexingDetailsIdentifier.getIndexingDetails(rule).getIndexType())
                .isEqualTo(NOT_INDEXED);
    }

    @Test
@@ -171,8 +179,8 @@ public class RuleIndexTypeIdentifierTest {
                                                                /* isHashedValue= */ false))))),
                        Rule.DENY);

        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
        assertThat(RuleIndexingDetailsIdentifier.getIndexingDetails(rule).getIndexType())
                .isEqualTo(NOT_INDEXED);
    }

    private Formula getInvalidFormula() {
@@ -215,4 +223,3 @@ public class RuleIndexTypeIdentifierTest {
        };
    }
}