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:
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user