Loading services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +26 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); Loading Loading @@ -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 { Loading services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +130 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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())); } Loading Loading @@ -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( Loading Loading
services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +26 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); Loading Loading @@ -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 { Loading
services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +130 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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())); } Loading Loading @@ -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( Loading