Loading core/java/android/content/res/Element.java +13 −3 Original line number Diff line number Diff line Loading @@ -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 = ";,[](){}:?%^*|/\\"; Loading Loading @@ -157,6 +159,7 @@ public class Element { } private long mChildTagMask = 0; private int mTotalComponentMetadataSize = 0; private static int getCounterIdx(String tag) { switch(tag) { Loading Loading @@ -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); Loading Loading @@ -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)]; Loading core/java/android/content/res/Validator.java +20 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -84,6 +86,9 @@ public class Validator { return; } mElements.peek().validateResStrAttr(index, stringValue); if (index == R.styleable.AndroidManifestMetaData_value) { validateComponentMetadata(stringValue.toString()); } } /** Loading @@ -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); } } } services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt +66 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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" Loading Loading
core/java/android/content/res/Element.java +13 −3 Original line number Diff line number Diff line Loading @@ -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 = ";,[](){}:?%^*|/\\"; Loading Loading @@ -157,6 +159,7 @@ public class Element { } private long mChildTagMask = 0; private int mTotalComponentMetadataSize = 0; private static int getCounterIdx(String tag) { switch(tag) { Loading Loading @@ -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); Loading Loading @@ -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)]; Loading
core/java/android/content/res/Validator.java +20 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -84,6 +86,9 @@ public class Validator { return; } mElements.peek().validateResStrAttr(index, stringValue); if (index == R.styleable.AndroidManifestMetaData_value) { validateComponentMetadata(stringValue.toString()); } } /** Loading @@ -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); } } }
services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt +66 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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" Loading