From 35e8f367b35718a8823c8f9a0a37dd71899d1963 Mon Sep 17 00:00:00 2001 From: Omer Nebil Yaveroglu Date: Fri, 17 Jan 2020 10:54:10 +0000 Subject: [PATCH] Put size limits on the number of rules that can be pushed through a verifier. Bug: 147865065 Test: atest FrameworksServicesTests:RuleBinarySerializerTest Change-Id: I7767fe9bc18761988b8ef19578d491183904984b --- .../serializer/RuleBinarySerializer.java | 26 ++++ .../serializer/RuleBinarySerializerTest.java | 134 +++++++++++++++++- 2 files changed, 156 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java index 6afadbad20545..f5ed975bf772a 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -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>> 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> 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 formatVersion, ByteTrackedOutputStream outputStream) throws IOException { diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java index 8ee5f5fb9de81..e5cbeee2860d3 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java @@ -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())); } @@ -203,8 +204,8 @@ public class RuleBinarySerializerTest { + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) + SERIALIZED_END_INDEXING_KEY + getBits( - DEFAULT_FORMAT_VERSION_BYTES.length + getBytes(expectedBits).length, - /* numOfBits= */ 32); + DEFAULT_FORMAT_VERSION_BYTES.length + getBytes(expectedBits).length, + /* numOfBits= */ 32); expectedIndexingOutputStream.write( getBytes( expectedIndexingBitsForIndexed @@ -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 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 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 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 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(