Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83d651f7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce a RuleIndexingParser class that will help us to identify the...

Merge "Introduce a RuleIndexingParser class that will help us to identify the range of the bytes to be read and parsed."
parents 9498a10f 4f5ceae9
Loading
Loading
Loading
Loading
+29 −3
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.integrity.parser.RuleBinaryParser;
import com.android.server.integrity.parser.RuleIndexingController;
import com.android.server.integrity.parser.RuleMetadataParser;
import com.android.server.integrity.parser.RuleParseException;
import com.android.server.integrity.parser.RuleParser;
@@ -61,7 +62,10 @@ public class IntegrityFileManager {
    // update rules atomically.
    private final File mStagingDir;

    @Nullable private RuleMetadata mRuleMetadataCache;
    @Nullable
    private RuleMetadata mRuleMetadataCache;
    @Nullable
    private RuleIndexingController mRuleIndexingController;

    /** Get the singleton instance of this class. */
    public static synchronized IntegrityFileManager getInstance() {
@@ -100,6 +104,8 @@ public class IntegrityFileManager {
                Slog.e(TAG, "Error reading metadata file.", e);
            }
        }

        updateRuleIndexingController();
    }

    /**
@@ -109,7 +115,8 @@ public class IntegrityFileManager {
     */
    public boolean initialized() {
        return new File(mRulesDir, RULES_FILE).exists()
                && new File(mRulesDir, METADATA_FILE).exists();
                && new File(mRulesDir, METADATA_FILE).exists()
                && new File(mRulesDir, INDEXING_FILE).exists();
    }

    /** Write rules to persistent storage. */
@@ -131,6 +138,9 @@ public class IntegrityFileManager {
        }

        switchStagingRulesDir();

        // Update object holding the indexing information.
        updateRuleIndexingController();
    }

    /**
@@ -140,8 +150,13 @@ public class IntegrityFileManager {
     */
    public List<Rule> readRules(AppInstallMetadata appInstallMetadata)
            throws IOException, RuleParseException {
        // TODO: select rules by index
        synchronized (RULES_LOCK) {
            // Try to identify indexes from the index file.
            List<List<Integer>> ruleReadingIndexes =
                    mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);

            // Read the rules based on the index information.
            // TODO(b/145493956): Provide the identified indexes to the rule reader.
            try (FileInputStream inputStream =
                         new FileInputStream(new File(mRulesDir, RULES_FILE))) {
                List<Rule> rules = mRuleParser.parse(inputStream);
@@ -168,6 +183,17 @@ public class IntegrityFileManager {
        }
    }

    private void updateRuleIndexingController() {
        File ruleIndexingFile = new File(mRulesDir, INDEXING_FILE);
        if (ruleIndexingFile.exists()) {
            try (FileInputStream inputStream = new FileInputStream(ruleIndexingFile)) {
                mRuleIndexingController = new RuleIndexingController(inputStream);
            } catch (Exception e) {
                Slog.e(TAG, "Error parsing the rule indexing file.", e);
            }
        }
    }

    private void writeMetadata(File directory, String ruleProvider, String version)
            throws IOException {
        mRuleMetadataCache = new RuleMetadata(ruleProvider, version);
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.integrity.model;

/**  A helper class containing special indexing file constants. */
public final class IndexingFileConstants {
    // The parsing time seems acceptable for this block size based on the tests in
    // go/ic-rule-file-format.
    public static final int INDEXING_BLOCK_SIZE = 100;

    public static final String START_INDEXING_KEY = "START_KEY";
    public static final String END_INDEXING_KEY = "END_KEY";
}
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.integrity.parser;

import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS;
import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;

import com.android.server.integrity.IntegrityUtils;
import com.android.server.integrity.model.BitInputStream;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * Helper methods for reading standard data structures from {@link BitInputStream}.
 */
public class BinaryFileOperations {

    /**
     * Read an string value with the given size and hash status from a {@code BitInputStream}.
     *
     * If the value is hashed, get the hex-encoding of the value. Serialized values are in raw form.
     * All hashed values are hex-encoded.
     */
    public static String getStringValue(BitInputStream bitInputStream) throws IOException {
        boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1;
        int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS);
        return getStringValue(bitInputStream, valueSize, isHashedValue);
    }

    /**
     * Read an string value with the given size and hash status from a {@code BitInputStream}.
     *
     * If the value is hashed, get the hex-encoding of the value. Serialized values are in raw form.
     * All hashed values are hex-encoded.
     */
    public static String getStringValue(
            BitInputStream bitInputStream, int valueSize, boolean isHashedValue)
            throws IOException {
        if (!isHashedValue) {
            StringBuilder value = new StringBuilder();
            while (valueSize-- > 0) {
                value.append((char) bitInputStream.getNext(/* numOfBits= */ 8));
            }
            return value.toString();
        }
        ByteBuffer byteBuffer = ByteBuffer.allocate(valueSize);
        while (valueSize-- > 0) {
            byteBuffer.put((byte) (bitInputStream.getNext(/* numOfBits= */ 8) & 0xFF));
        }
        return IntegrityUtils.getHexDigest(byteBuffer.array());
    }

    /** Read an integer value from a {@code BitInputStream}. */
    public static int getIntValue(BitInputStream bitInputStream) throws IOException {
        return bitInputStream.getNext(/* numOfBits= */ 32);
    }

    /** Read an boolean value from a {@code BitInputStream}. */
    public static boolean getBooleanValue(BitInputStream bitInputStream) throws IOException {
        return bitInputStream.getNext(/* numOfBits= */ 1) == 1;
    }
}
+3 −31
Original line number Diff line number Diff line
@@ -28,18 +28,19 @@ import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
import static com.android.server.integrity.model.ComponentBitSize.SIGNAL_BIT;
import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
import static com.android.server.integrity.parser.BinaryFileOperations.getBooleanValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;

import android.content.integrity.AtomicFormula;
import android.content.integrity.CompoundFormula;
import android.content.integrity.Formula;
import android.content.integrity.Rule;

import com.android.server.integrity.IntegrityUtils;
import com.android.server.integrity.model.BitInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

@@ -145,33 +146,4 @@ public class RuleBinaryParser implements RuleParser {
                throw new IllegalArgumentException(String.format("Unknown key: %d", key));
        }
    }

    // Get value string from stream.
    // If the value is not hashed, get its raw form directly.
    // If the value is hashed, get the hex-encoding of the value. Serialized values are in raw form.
    // All hashed values are hex-encoded.
    private static String getStringValue(
            BitInputStream bitInputStream, int valueSize, boolean isHashedValue)
            throws IOException {
        if (!isHashedValue) {
            StringBuilder value = new StringBuilder();
            while (valueSize-- > 0) {
                value.append((char) bitInputStream.getNext(/* numOfBits= */ 8));
            }
            return value.toString();
        }
        ByteBuffer byteBuffer = ByteBuffer.allocate(valueSize);
        while (valueSize-- > 0) {
            byteBuffer.put((byte) (bitInputStream.getNext(/* numOfBits= */ 8) & 0xFF));
        }
        return IntegrityUtils.getHexDigest(byteBuffer.array());
    }

    private static int getIntValue(BitInputStream bitInputStream) throws IOException {
        return bitInputStream.getNext(/* numOfBits= */ 32);
    }

    private static boolean getBooleanValue(BitInputStream bitInputStream) throws IOException {
        return bitInputStream.getNext(/* numOfBits= */ 1) == 1;
    }
}
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.integrity.parser;

import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;

import android.content.integrity.AppInstallMetadata;

import com.android.server.integrity.model.BitInputStream;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

/** Helper class to identify the necessary indexes that needs to be read. */
public class RuleIndexingController {

    private static TreeMap<String, Integer> sPackageNameBasedIndexes;
    private static TreeMap<String, Integer> sAppCertificateBasedIndexes;
    private static TreeMap<String, Integer> sUnindexedRuleIndexes;

    /**
     * Provide the indexing file to read and the object will be constructed by reading and
     * identifying the indexes.
     */
    public RuleIndexingController(FileInputStream fileInputStream) throws IOException {
        BitInputStream bitInputStream = new BitInputStream(fileInputStream);
        sPackageNameBasedIndexes = getNextIndexGroup(bitInputStream);
        sAppCertificateBasedIndexes = getNextIndexGroup(bitInputStream);
        sUnindexedRuleIndexes = getNextIndexGroup(bitInputStream);
    }

    /**
     * Returns a list of integers with the starting and ending bytes of the rules that needs to be
     * read and evaluated.
     */
    public List<List<Integer>> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
        // TODO(b/145493956): Identify and return the indexes that needs to be read.
        return new ArrayList<>();
    }

    private TreeMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
            throws IOException {
        TreeMap<String, Integer> keyToIndexMap = new TreeMap<>();
        while (bitInputStream.hasNext()) {
            String key = getStringValue(bitInputStream);
            int value = getIntValue(bitInputStream);

            keyToIndexMap.put(key, value);

            if (key == END_INDEXING_KEY) {
                break;
            }
        }
        return keyToIndexMap;
    }
}
Loading