Modify the RuleBinaryParser to only parse the ranges that are within the

index ranges.

Bug: 145493956
Test: atest FrameworksServicesTests:RuleBinaryParserTest
Change-Id: I5a453cf49b937fa4516ae9939ec6d7bba02e7ac0
This commit is contained in:
Omer Nebil Yaveroglu
2020-01-09 16:24:28 +00:00
parent 918e0ec580
commit 053ee29ff0
6 changed files with 139 additions and 33 deletions

View File

@@ -39,6 +39,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -153,14 +154,19 @@ public class IntegrityFileManager {
throws IOException, RuleParseException {
synchronized (RULES_LOCK) {
// Try to identify indexes from the index file.
List<RuleIndexRange> ruleReadingIndexes =
mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
List<RuleIndexRange> ruleReadingIndexes;
try {
ruleReadingIndexes =
mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
} catch (Exception e) {
Slog.w(TAG, "Error identifying the rule indexes. Trying unindexed.", e);
ruleReadingIndexes = Collections.emptyList();
}
// Read the rules based on the index information.
// TODO(b/145493956): Provide the identified indexes to the rule reader.
// Read the rules based on the index information when available.
try (FileInputStream inputStream =
new FileInputStream(new File(mRulesDir, RULES_FILE))) {
List<Rule> rules = mRuleParser.parse(inputStream);
List<Rule> rules = mRuleParser.parse(inputStream, ruleReadingIndexes);
return rules;
}
}

View File

@@ -42,6 +42,7 @@ import com.android.server.integrity.model.BitTrackedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** A helper class to parse rules into the {@link Rule} model from Binary representation. */
@@ -51,28 +52,40 @@ public class RuleBinaryParser implements RuleParser {
public List<Rule> parse(byte[] ruleBytes) throws RuleParseException {
try {
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(ruleBytes);
return parseRules(bitTrackedInputStream);
return parseRules(bitTrackedInputStream, /* indexRanges= */ Collections.emptyList());
} catch (Exception e) {
throw new RuleParseException(e.getMessage(), e);
}
}
@Override
public List<Rule> parse(InputStream inputStream) throws RuleParseException {
public List<Rule> parse(InputStream inputStream, List<RuleIndexRange> indexRanges)
throws RuleParseException {
try {
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(inputStream);
return parseRules(bitTrackedInputStream);
return parseRules(bitTrackedInputStream, indexRanges);
} catch (Exception e) {
throw new RuleParseException(e.getMessage(), e);
}
}
private List<Rule> parseRules(BitTrackedInputStream bitTrackedInputStream) throws IOException {
List<Rule> parsedRules = new ArrayList<>();
private List<Rule> parseRules(
BitTrackedInputStream bitTrackedInputStream,
List<RuleIndexRange> indexRanges)
throws IOException {
// Read the rule binary file format version.
bitTrackedInputStream.getNext(FORMAT_VERSION_BITS);
return indexRanges.isEmpty()
? parseAllRules(bitTrackedInputStream)
: parseIndexedRules(bitTrackedInputStream, indexRanges);
}
private List<Rule> parseAllRules(BitTrackedInputStream bitTrackedInputStream)
throws IOException {
List<Rule> parsedRules = new ArrayList<>();
while (bitTrackedInputStream.hasNext()) {
if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) {
parsedRules.add(parseRule(bitTrackedInputStream));
@@ -82,6 +95,27 @@ public class RuleBinaryParser implements RuleParser {
return parsedRules;
}
private List<Rule> parseIndexedRules(
BitTrackedInputStream bitTrackedInputStream, List<RuleIndexRange> indexRanges)
throws IOException {
List<Rule> parsedRules = new ArrayList<>();
for (RuleIndexRange range : indexRanges) {
// Skip the rules that are not in the range.
bitTrackedInputStream.setCursorToByteLocation(range.getStartIndex());
// Read the rules until we reach the end index.
while (bitTrackedInputStream.hasNext()
&& bitTrackedInputStream.getReadBitsCount() < range.getEndIndex()) {
if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) {
parsedRules.add(parseRule(bitTrackedInputStream));
}
}
}
return parsedRules;
}
private Rule parseRule(BitTrackedInputStream bitTrackedInputStream) throws IOException {
Formula formula = parseFormula(bitTrackedInputStream);
int effect = bitTrackedInputStream.getNext(EFFECT_BITS);

View File

@@ -28,5 +28,6 @@ public interface RuleParser {
List<Rule> parse(byte[] ruleBytes) throws RuleParseException;
/** Parse rules from an input stream. */
List<Rule> parse(InputStream inputStream) throws RuleParseException;
List<Rule> parse(InputStream inputStream, List<RuleIndexRange> ruleIndexRanges)
throws RuleParseException;
}

View File

@@ -62,7 +62,8 @@ public final class RuleXmlParser implements RuleParser {
}
@Override
public List<Rule> parse(InputStream inputStream) throws RuleParseException {
public List<Rule> parse(InputStream inputStream, List<RuleIndexRange> indexRanges)
throws RuleParseException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());

View File

@@ -48,6 +48,7 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -97,8 +98,10 @@ public class RuleBinaryParserTest {
private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
private static final List<RuleIndexRange> NO_INDEXING = Collections.emptyList();
@Test
public void testBinaryStream_validCompoundFormula() throws Exception {
public void testBinaryStream_validCompoundFormula_noIndexing() throws Exception {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -131,13 +134,13 @@ public class RuleBinaryParserTest {
/* isHashedValue= */ false))),
Rule.DENY);
List<Rule> rules = binaryParser.parse(inputStream);
List<Rule> rules = binaryParser.parse(inputStream, NO_INDEXING);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testBinaryString_validCompoundFormula_notConnector() throws Exception {
public void testBinaryString_validCompoundFormula_notConnector_noIndexing() throws Exception {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -175,7 +178,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_validCompoundFormula_andConnector() throws Exception {
public void testBinaryString_validCompoundFormula_andConnector_noIndexing() throws Exception {
String packageName = "com.test.app";
String appCertificate = "test_cert";
String ruleBits =
@@ -223,7 +226,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_validCompoundFormula_orConnector() throws Exception {
public void testBinaryString_validCompoundFormula_orConnector_noIndexing() throws Exception {
String packageName = "com.test.app";
String appCertificate = "test_cert";
String ruleBits =
@@ -272,7 +275,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_validAtomicFormula_stringValue() throws Exception {
public void testBinaryString_validAtomicFormula_stringValue_noIndexing() throws Exception {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -304,7 +307,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_validAtomicFormula_hashedValue() throws Exception {
public void testBinaryString_validAtomicFormula_hashedValue_noIndexing() throws Exception {
String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
String ruleBits =
START_BIT
@@ -337,7 +340,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_validAtomicFormula_integerValue() throws Exception {
public void testBinaryString_validAtomicFormula_integerValue_noIndexing() throws Exception {
int versionCode = 1;
String ruleBits =
START_BIT
@@ -365,7 +368,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_validAtomicFormula_booleanValue() throws Exception {
public void testBinaryString_validAtomicFormula_booleanValue_noIndexing() throws Exception {
String isPreInstalled = "1";
String ruleBits =
START_BIT
@@ -392,7 +395,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidAtomicFormula() throws Exception {
public void testBinaryString_invalidAtomicFormula_noIndexing() {
int versionCode = 1;
String ruleBits =
START_BIT
@@ -415,7 +418,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_withNoRuleList() throws RuleParseException {
public void testBinaryString_withNoRuleList_noIndexing() throws RuleParseException {
ByteBuffer rule = ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length);
rule.put(DEFAULT_FORMAT_VERSION_BYTES);
RuleParser binaryParser = new RuleBinaryParser();
@@ -426,7 +429,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_withEmptyRule() throws RuleParseException {
public void testBinaryString_withEmptyRule_noIndexing() {
String ruleBits = START_BIT;
byte[] ruleBytes = getBytes(ruleBits);
ByteBuffer rule =
@@ -442,7 +445,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas() throws Exception {
public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas_noIndexing() {
String packageName = "com.test.app";
String appCertificate = "test_cert";
String ruleBits =
@@ -478,7 +481,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidRule_invalidOperator() throws Exception {
public void testBinaryString_invalidRule_invalidOperator_noIndexing() {
int versionCode = 1;
String ruleBits =
START_BIT
@@ -506,7 +509,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidRule_invalidEffect() throws Exception {
public void testBinaryString_invalidRule_invalidEffect_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -536,7 +539,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidRule_invalidConnector() throws Exception {
public void testBinaryString_invalidRule_invalidConnector_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -566,7 +569,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidRule_invalidKey() throws Exception {
public void testBinaryString_invalidRule_invalidKey_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -596,7 +599,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidRule_invalidSeparator() throws Exception {
public void testBinaryString_invalidRule_invalidSeparator_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -626,7 +629,7 @@ public class RuleBinaryParserTest {
}
@Test
public void testBinaryString_invalidRule_invalidEndMarker() throws Exception {
public void testBinaryString_invalidRule_invalidEndMarker_noIndexing() {
String packageName = "com.test.app";
String ruleBits =
START_BIT
@@ -653,4 +656,65 @@ public class RuleBinaryParserTest {
/* expectedExceptionMessageRegex */ "A rule must end with a '1' bit",
() -> binaryParser.parse(rule.array()));
}
@Test
public void testBinaryStream_multipleRules_indexingIdentifiesParsesIndexRangeCorrectly()
throws Exception {
String packageName2 = "com.test.2";
byte[] ruleBytes1 = getBytes(getRulesWithPackageName("com.test.1"));
byte[] ruleBytes2 = getBytes(getRulesWithPackageName(packageName2));
byte[] ruleBytes3 = getBytes(getRulesWithPackageName("com.test.3"));
ByteBuffer rule =
ByteBuffer.allocate(
DEFAULT_FORMAT_VERSION_BYTES.length
+ ruleBytes1.length
+ ruleBytes2.length
+ ruleBytes3.length);
rule.put(DEFAULT_FORMAT_VERSION_BYTES);
rule.put(ruleBytes1);
rule.put(ruleBytes2);
rule.put(ruleBytes3);
InputStream inputStream = new ByteArrayInputStream(rule.array());
RuleParser binaryParser = new RuleBinaryParser();
List<RuleIndexRange> indexRanges = new ArrayList<>();
indexRanges.add(
new RuleIndexRange(
DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes1.length,
DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes1.length
+ ruleBytes2.length));
List<Rule> rules = binaryParser.parse(inputStream, indexRanges);
Rule expectedRule =
new Rule(
new CompoundFormula(
CompoundFormula.NOT,
Collections.singletonList(
new AtomicFormula.StringAtomicFormula(
AtomicFormula.PACKAGE_NAME,
packageName2,
/* isHashedValue= */ false))),
Rule.DENY);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
private static String getRulesWithPackageName(String packageName) {
return START_BIT
+ COMPOUND_FORMULA_START_BITS
+ NOT
+ ATOMIC_FORMULA_START_BITS
+ PACKAGE_NAME
+ EQ
+ IS_NOT_HASHED
+ getBits(packageName.length(), VALUE_SIZE_BITS)
+ getValueBits(packageName)
+ COMPOUND_FORMULA_END_BITS
+ DENY
+ END_BIT;
}
}

View File

@@ -73,7 +73,7 @@ public class RuleXmlParserTest {
/* isHashedValue= */ false))),
Rule.DENY);
List<Rule> rules = xmlParser.parse(inputStream);
List<Rule> rules = xmlParser.parse(inputStream, Collections.emptyList());
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@@ -623,7 +623,7 @@ public class RuleXmlParserTest {
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
() -> xmlParser.parse(inputStream));
() -> xmlParser.parse(inputStream, Collections.emptyList()));
}
private String generateTagWithAttribute(