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

Commit 9e79ad8b authored by William Loh's avatar William Loh Committed by Android (Google) Code Review
Browse files

Merge "Limit max meta data string values per component." into main

parents 177a544d 21c90e0c
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -38,9 +38,11 @@ public class Element {
    private static final int MAX_ATTR_LEN_PERMISSION_GROUP = 256;
    private static final int MAX_ATTR_LEN_PACKAGE = 256;
    private static final int MAX_ATTR_LEN_MIMETYPE = 512;
    public static final int MAX_ATTR_LEN_NAME = 1024;
    public static final int MAX_ATTR_LEN_PATH = 4000;
    public static final int MAX_ATTR_LEN_VALUE = 32_768;
    private static final int MAX_ATTR_LEN_NAME = 1024;
    private static final int MAX_ATTR_LEN_PATH = 4000;
    private static final int MAX_ATTR_LEN_VALUE = 32_768;

    private static final int MAX_TOTAL_META_DATA_SIZE = 262_144;

    private static final String BAD_COMPONENT_NAME_CHARS = ";,[](){}:?%^*|/\\";

@@ -157,6 +159,7 @@ public class Element {
    }

    private long mChildTagMask = 0;
    private int mTotalComponentMetadataSize = 0;

    private static int getCounterIdx(String tag) {
        switch(tag) {
@@ -283,6 +286,7 @@ public class Element {
    private void init(String tag) {
        this.mTag = tag;
        mChildTagMask = 0;
        mTotalComponentMetadataSize = 0;
        switch (tag) {
            case TAG_ACTIVITY:
                initializeCounter(TAG_LAYOUT, 1000);
@@ -820,6 +824,12 @@ public class Element {
        }
    }

    void validateComponentMetadata(String value) {
        mTotalComponentMetadataSize += value.length();
        if (mTotalComponentMetadataSize > MAX_TOTAL_META_DATA_SIZE) {
            throw new SecurityException("Max total meta data size limit exceeded for " + mTag);
        }
    }

    void seen(@NonNull Element element) {
        TagCounter counter = mTagCounters[getCounterIdx(element.mTag)];
+20 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package android.content.res;
import android.annotation.NonNull;
import android.annotation.StyleableRes;

import com.android.internal.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

@@ -84,6 +86,9 @@ public class Validator {
            return;
        }
        mElements.peek().validateResStrAttr(index, stringValue);
        if (index == R.styleable.AndroidManifestMetaData_value) {
            validateComponentMetadata(stringValue.toString());
        }
    }

    /**
@@ -94,5 +99,20 @@ public class Validator {
            return;
        }
        mElements.peek().validateStrAttr(attrName, attrValue);
        if (attrName.equals(Element.TAG_ATTR_VALUE)) {
            validateComponentMetadata(attrValue);
        }
    }

    private void validateComponentMetadata(String attrValue) {
        Element element = mElements.peek();
        // Meta-data values are evaluated on the parent element which is the next element in the
        // mElements stack after the meta-data element. The top of the stack is always the current
        // element being validated so check that the top element is meta-data.
        if (element.mTag.equals(Element.TAG_META_DATA) && mElements.size() > 1) {
            element = mElements.pop();
            mElements.peek().validateComponentMetadata(attrValue);
            mElements.push(element);
        }
    }
}
+66 −0
Original line number Diff line number Diff line
@@ -492,6 +492,40 @@ class AndroidPackageParsingValidationTest {
        validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesPermission_name, 1024)
    }

    @Test
    fun totalMetadataValuesExceedMax_shouldFail() {
        val value = "x".repeat(8192)
        var tags = ""
        repeat(32) { index ->
            tags += "<meta-data name=\"name$index\" value=\"$value\" />"
        }
        var xml = "<application>$tags</application>"
        try {
            parseXmlForMetadata(xml)
        } catch (e: SecurityException) {
            fail(
                "Failed to parse component meta-data when values have not exceeded max allowed"
            )
        }
        try {
            parseXmlForMetadataRes(xml)
        } catch (e: SecurityException) {
            fail(
                "Failed to parse component meta-data when values have not exceeded max allowed"
            )
        }
        tags += "<meta-data name=\"last\" value=\"x\" />"
        xml = "<application>$tags</application>"
        var e = assertThrows(SecurityException::class.java) {
            parseXmlForMetadata(xml)
        }
        assertEquals("Max total meta data size limit exceeded for application", e.message)
        e = assertThrows(SecurityException::class.java) {
            parseXmlForMetadataRes(xml)
        }
        assertEquals("Max total meta data size limit exceeded for application", e.message)
    }

    private fun validateTagAttrComponentName(tag: String, attr: String, index: Int) {
        val passNames = arrayOf("com.android.TestClass", "TestClass", "_", "$", ".TestClass", "上")
        for (name in passNames) {
@@ -664,6 +698,38 @@ class AndroidPackageParsingValidationTest {
        } while (type != XmlPullParser.END_DOCUMENT)
    }

    fun parseXmlForMetadata(manifestStr: String) {
        pullParser.setInput(ByteArrayInputStream(manifestStr.toByteArray()), null)
        val validator = Validator()
        do {
            val type = pullParser.next()
            validator.validate(pullParser)
            if (type == XmlPullParser.START_TAG && pullParser.getName().equals("meta-data")) {
                val name = "value"
                val value = pullParser.getAttributeValue("", name)
                validator.validateStrAttr(pullParser, "value", value)
            }
        } while (type != XmlPullParser.END_DOCUMENT)
    }

    fun parseXmlForMetadataRes(manifestStr: String) {
        pullParser.setInput(ByteArrayInputStream(manifestStr.toByteArray()), null)
        val validator = Validator()
        do {
            val type = pullParser.next()
            validator.validate(pullParser)
            if (type == XmlPullParser.START_TAG && pullParser.getName().equals("meta-data")) {
                val name = "value"
                val value = pullParser.getAttributeValue("", name)
                validator.validateResStrAttr(
                    pullParser,
                    R.styleable.AndroidManifestMetaData_value,
                    value
                )
            }
        } while (type != XmlPullParser.END_DOCUMENT)
    }

    fun expectedCountErrorMsg(tag: String, parentTag: String) =
            "The number of child $tag elements exceeded the max allowed in $parentTag"