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

Commit c6eeb791 authored by Ömer Nebil Yaveroğlu's avatar Ömer Nebil Yaveroğlu Committed by Android (Google) Code Review
Browse files

Merge "Put size limits on the number of rules that can be pushed through a verifier."

parents 948cf18e 35e8f367
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ import java.util.stream.Collectors;

/** A helper class to serialize rules from the {@link Rule} model to Binary representation. */
public class RuleBinarySerializer implements RuleSerializer {
    static final int TOTAL_RULE_SIZE_LIMIT = 200000;
    static final int INDEXED_RULE_SIZE_LIMIT = 100000;
    static final int NONINDEXED_RULE_SIZE_LIMIT = 1000;

    // Get the byte representation for a list of rules.
    @Override
@@ -79,10 +82,23 @@ public class RuleBinarySerializer implements RuleSerializer {
            OutputStream indexingFileOutputStream)
            throws RuleSerializeException {
        try {
            if (rules == null) {
                throw new IllegalArgumentException("Null rules cannot be serialized.");
            }

            if (rules.size() > TOTAL_RULE_SIZE_LIMIT) {
                throw new IllegalArgumentException("Too many rules provided.");
            }

            // Determine the indexing groups and the order of the rules within each indexed group.
            Map<Integer, Map<String, List<Rule>>> indexedRules =
                    RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules);

            // Validate the rule blocks are not larger than expected limits.
            verifySize(indexedRules.get(PACKAGE_NAME_INDEXED), INDEXED_RULE_SIZE_LIMIT);
            verifySize(indexedRules.get(APP_CERTIFICATE_INDEXED), INDEXED_RULE_SIZE_LIMIT);
            verifySize(indexedRules.get(NOT_INDEXED), NONINDEXED_RULE_SIZE_LIMIT);

            // Serialize the rules.
            ByteTrackedOutputStream ruleFileByteTrackedOutputStream =
                    new ByteTrackedOutputStream(rulesFileOutputStream);
@@ -112,6 +128,16 @@ public class RuleBinarySerializer implements RuleSerializer {
        }
    }

    private void verifySize(Map<String, List<Rule>> ruleListMap, int ruleSizeLimit) {
        int totalRuleCount =
                ruleListMap.values().stream()
                        .map(list -> list.size())
                        .collect(Collectors.summingInt(Integer::intValue));
        if (totalRuleCount > ruleSizeLimit) {
            throw new IllegalArgumentException("Too many rules provided in the indexing group.");
        }
    }

    private void serializeRuleFileMetadata(
            Optional<Integer> formatVersion, ByteTrackedOutputStream outputStream)
            throws IOException {
+130 −4
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BIT
import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE;
import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
import static com.android.server.integrity.serializer.RuleBinarySerializer.INDEXED_RULE_SIZE_LIMIT;
import static com.android.server.integrity.serializer.RuleBinarySerializer.NONINDEXED_RULE_SIZE_LIMIT;
import static com.android.server.integrity.utils.TestUtils.getBits;
import static com.android.server.integrity.utils.TestUtils.getBytes;
import static com.android.server.integrity.utils.TestUtils.getValueBits;
@@ -112,8 +114,7 @@ public class RuleBinarySerializerTest {

        assertExpectException(
                RuleSerializeException.class,
                /* expectedExceptionMessageRegex= */ "Index buckets cannot be created for null"
                        + " rule list.",
                /* expectedExceptionMessageRegex= */ "Null rules cannot be serialized.",
                () -> binarySerializer.serialize(null, /* formatVersion= */ Optional.empty()));
    }

@@ -618,6 +619,131 @@ public class RuleBinarySerializerTest {
                .isEqualTo(expectedIndexingOutputStream.toByteArray());
    }

    @Test
    public void testBinaryString_totalRuleSizeLimitReached() {
        int ruleCount = INDEXED_RULE_SIZE_LIMIT - 1;
        String packagePrefix = "package.name.";
        String appCertificatePrefix = "app.cert.";
        String installerNamePrefix = "installer.";

        // Create the rule set with more rules than the system can handle in total.
        List<Rule> ruleList = new ArrayList();
        for (int count = 0; count < ruleCount; count++) {
            ruleList.add(
                    getRuleWithPackageNameAndSampleInstallerName(
                            String.format("%s%04d", packagePrefix, count)));
        }
        for (int count = 0; count < ruleCount; count++) {
            ruleList.add(
                    getRuleWithAppCertificateAndSampleInstallerName(
                            String.format("%s%04d", appCertificatePrefix, count)));
        }
        for (int count = 0; count < NONINDEXED_RULE_SIZE_LIMIT - 1; count++) {
            ruleList.add(
                    getNonIndexedRuleWithInstallerName(
                            String.format("%s%04d", installerNamePrefix, count)));
        }

        // Serialize the rules.
        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
        RuleSerializer binarySerializer = new RuleBinarySerializer();

        assertExpectException(
                RuleSerializeException.class,
                "Too many rules provided",
                () ->
                        binarySerializer.serialize(
                                ruleList,
                                /* formatVersion= */ Optional.empty(),
                                ruleOutputStream,
                                indexingOutputStream));
    }

    @Test
    public void testBinaryString_tooManyPackageNameIndexedRules() {
        String packagePrefix = "package.name.";

        // Create a rule set with too many package name indexed rules.
        List<Rule> ruleList = new ArrayList();
        for (int count = 0; count < INDEXED_RULE_SIZE_LIMIT + 1; count++) {
            ruleList.add(
                    getRuleWithPackageNameAndSampleInstallerName(
                            String.format("%s%04d", packagePrefix, count)));
        }

        // Serialize the rules.
        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
        RuleSerializer binarySerializer = new RuleBinarySerializer();

        assertExpectException(
                RuleSerializeException.class,
                "Too many rules provided in the indexing group.",
                () ->
                        binarySerializer.serialize(
                                ruleList,
                                /* formatVersion= */ Optional.empty(),
                                ruleOutputStream,
                                indexingOutputStream));
    }

    @Test
    public void testBinaryString_tooManyAppCertificateIndexedRules() {
        String appCertificatePrefix = "app.cert.";

        // Create a rule set with too many app certificate indexed rules.
        List<Rule> ruleList = new ArrayList();
        for (int count = 0; count < INDEXED_RULE_SIZE_LIMIT + 1; count++) {
            ruleList.add(
                    getRuleWithAppCertificateAndSampleInstallerName(
                            String.format("%s%04d", appCertificatePrefix, count)));
        }

        // Serialize the rules.
        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
        RuleSerializer binarySerializer = new RuleBinarySerializer();

        assertExpectException(
                RuleSerializeException.class,
                "Too many rules provided in the indexing group.",
                () ->
                        binarySerializer.serialize(
                                ruleList,
                                /* formatVersion= */ Optional.empty(),
                                ruleOutputStream,
                                indexingOutputStream));
    }

    @Test
    public void testBinaryString_tooManyNonIndexedRules() {
        String installerNamePrefix = "installer.";

        // Create a rule set with too many unindexed rules.
        List<Rule> ruleList = new ArrayList();
        for (int count = 0; count < NONINDEXED_RULE_SIZE_LIMIT + 1; count++) {
            ruleList.add(
                    getNonIndexedRuleWithInstallerName(
                            String.format("%s%04d", installerNamePrefix, count)));
        }

        // Serialize the rules.
        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
        RuleSerializer binarySerializer = new RuleBinarySerializer();

        assertExpectException(
                RuleSerializeException.class,
                "Too many rules provided in the indexing group.",
                () ->
                        binarySerializer.serialize(
                                ruleList,
                                /* formatVersion= */ Optional.empty(),
                                ruleOutputStream,
                                indexingOutputStream));
    }

    private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) {
        return new Rule(
                new CompoundFormula(