Put size limits on the number of rules that can be

pushed through a verifier.

Bug: 147865065
Test: atest FrameworksServicesTests:RuleBinarySerializerTest
Change-Id: I7767fe9bc18761988b8ef19578d491183904984b
This commit is contained in:
Omer Nebil Yaveroglu
2020-01-17 10:54:10 +00:00
parent aa6e958606
commit 35e8f367b3
2 changed files with 156 additions and 4 deletions

View File

@@ -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 {

View File

@@ -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<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(