Loading core/java/android/content/res/Element.java +105 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.os.SystemProperties.PROP_VALUE_MAX; import android.annotation.NonNull; import android.util.Pools.SimplePool; import android.util.Slog; import androidx.annotation.StyleableRes; Loading @@ -41,6 +42,7 @@ public class Element { public static final int MAX_ATTR_LEN_PATH = 4000; public static final int MAX_ATTR_LEN_DATA_VALUE = 4000; private static final String TAG = "PackageParsing"; protected static final String TAG_ACTION = "action"; protected static final String TAG_ACTIVITY = "activity"; protected static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; Loading Loading @@ -715,22 +717,125 @@ public class Element { mChildTagMask |= 1 << idx; } private boolean isComponentNameAttr(String name) { switch (mTag) { case TAG_ACTIVITY: switch (name) { case TAG_ATTR_NAME: case TAG_ATTR_PARENT_ACTIVITY_NAME: return true; default: return false; } case TAG_ACTIVITY_ALIAS: switch (name) { case TAG_ATTR_TARGET_ACTIVITY: return true; default: return false; } case TAG_APPLICATION: switch (name) { case TAG_ATTR_BACKUP_AGENT: case TAG_ATTR_NAME: return true; default: return false; } case TAG_INSTRUMENTATION: case TAG_PROVIDER: case TAG_RECEIVER: case TAG_SERVICE: case TAG_USES_LIBRARY: switch (name) { case TAG_ATTR_NAME: return true; default: return false; } default: return false; } } private boolean isComponentNameAttr(@StyleableRes int index) { switch (mTag) { case TAG_ACTIVITY: return index == R.styleable.AndroidManifestActivity_name || index == R.styleable.AndroidManifestActivity_parentActivityName; case TAG_ACTIVITY_ALIAS: return index == R.styleable.AndroidManifestActivityAlias_targetActivity; case TAG_APPLICATION: return index == R.styleable.AndroidManifestApplication_backupAgent || index == R.styleable.AndroidManifestApplication_name; case TAG_INSTRUMENTATION: return index == R.styleable.AndroidManifestInstrumentation_name; case TAG_PROVIDER: return index == R.styleable.AndroidManifestProvider_name; case TAG_RECEIVER: return index == R.styleable.AndroidManifestReceiver_name; case TAG_SERVICE: return index == R.styleable.AndroidManifestService_name; case TAG_USES_LIBRARY: return index == R.styleable.AndroidManifestUsesLibrary_name; default: return false; } } boolean hasChild(String tag) { return (mChildTagMask & (1 << getCounterIdx(tag))) != 0; } void validateComponentName(CharSequence name) { int i = 0; if (name.charAt(0) == '.') { i = 1; } boolean isStart = true; for (; i < name.length(); i++) { if (name.charAt(i) == '.') { if (isStart) { break; } isStart = true; } else { if (isStart) { if (Character.isJavaIdentifierStart(name.charAt(i))) { isStart = false; } else { break; } } else if (!Character.isJavaIdentifierPart(name.charAt(i))) { break; } } } if ((i < name.length()) || (name.charAt(name.length() - 1) == '.')) { Slog.e(TAG, name + " is not a valid Java class name"); throw new SecurityException(name + " is not a valid Java class name"); } } void validateStrAttr(String attrName, String attrValue) { if (attrValue != null && attrValue.length() > getAttrStrMaxLen(attrName)) { throw new SecurityException("String length limit exceeded for attribute " + attrName + " in " + mTag); } if (isComponentNameAttr(attrName)) { validateComponentName(attrValue); } } void validateResStrAttr(@StyleableRes int index, CharSequence stringValue) { if (stringValue != null && stringValue.length() > getResStrMaxLen(index)) { throw new SecurityException("String length limit exceeded for attribute in " + mTag); } if (isComponentNameAttr(index)) { validateComponentName(stringValue); } } void seen(@NonNull Element element) { TagCounter counter = mTagCounters[getCounterIdx(element.mTag)]; Loading services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt +59 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,6 @@ class AndroidPackageParsingValidationTest { factory.isNamespaceAware = true factory.newPullParser() } private val ns = "xmlns:android=\"http://schemas.android.com/apk/res/android\"" } @Test Loading Loading @@ -102,9 +101,13 @@ class AndroidPackageParsingValidationTest { val tag = "application" validateTagAttr(tag, "backupAgent", R.styleable.AndroidManifestApplication_backupAgent, 1024) validateTagAttrComponentName(tag, "backupAgent", R.styleable.AndroidManifestApplication_backupAgent) validateTagAttr(tag, "manageSpaceActivity", R.styleable.AndroidManifestApplication_manageSpaceActivity, 1024) validateTagAttr(tag, "name", R.styleable.AndroidManifestApplication_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestApplication_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestApplication_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestApplication_process, 1024) validateTagAttr(tag, "requiredAccountType", Loading Loading @@ -134,6 +137,7 @@ class AndroidPackageParsingValidationTest { fun parseReceiverTag() { val tag = "receiver" validateTagAttr(tag, "name", R.styleable.AndroidManifestReceiver_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestReceiver_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestReceiver_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestReceiver_process, 1024) validateTagCount("meta-data", 1000, tag) Loading @@ -144,6 +148,7 @@ class AndroidPackageParsingValidationTest { fun parseServiceTag() { val tag = "service" validateTagAttr(tag, "name", R.styleable.AndroidManifestService_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestService_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestService_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestService_process, 1024) validateTagCount("meta-data", 1000, tag) Loading @@ -158,6 +163,8 @@ class AndroidPackageParsingValidationTest { R.styleable.AndroidManifestActivityAlias_permission, 1024) validateTagAttr(tag, "targetActivity", R.styleable.AndroidManifestActivityAlias_targetActivity, 1024) validateTagAttrComponentName(tag, "targetActivity", R.styleable.AndroidManifestActivityAlias_targetActivity) validateTagCount("meta-data", 1000, tag) validateTagCount("intent-filter", 20000, tag) } Loading @@ -166,14 +173,18 @@ class AndroidPackageParsingValidationTest { fun parseUsesLibraryTag() { val tag = "uses-library" validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesLibrary_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestUsesLibrary_name) } @Test fun parseActivityTag() { val tag = "activity" validateTagAttr(tag, "name", R.styleable.AndroidManifestActivity_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestActivity_name) validateTagAttr(tag, "parentActivityName", R.styleable.AndroidManifestActivity_parentActivityName, 1024) validateTagAttrComponentName(tag, "parentActivityName", R.styleable.AndroidManifestActivity_parentActivityName) validateTagAttr(tag, "permission", R.styleable.AndroidManifestActivity_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestActivity_process, 1024) validateTagAttr(tag, "taskAffinity", R.styleable.AndroidManifestActivity_taskAffinity, 1024) Loading @@ -200,6 +211,8 @@ class AndroidPackageParsingValidationTest { fun parseInstrumentationTag() { val tag = "instrumentation" validateTagAttr(tag, "name", R.styleable.AndroidManifestInstrumentation_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestInstrumentation_name) validateTagAttr(tag, "targetPackage", R.styleable.AndroidManifestInstrumentation_targetPackage, 256) validateTagAttr(tag, "targetProcesses", Loading Loading @@ -262,6 +275,7 @@ class AndroidPackageParsingValidationTest { fun parseProviderTag() { val tag = "provider" validateTagAttr(tag, "name", R.styleable.AndroidManifestProvider_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestProvider_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestProvider_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestProvider_process, 1024) validateTagAttr(tag, "readPermission", Loading Loading @@ -361,6 +375,48 @@ class AndroidPackageParsingValidationTest { validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesPermission_name, 1024) } private fun validateTagAttrComponentName(tag: String, attr: String, index: Int) { val passNames = arrayOf("com.android.TestClass", "TestClass", "_", "$", ".TestClass", "上") for (name in passNames) { val xml = "<$tag $attr=\"$name\" />" pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null) val validator = Validator() pullParser.nextTag() validator.validate(pullParser) try { validator.validateStrAttr(pullParser, attr, name) } catch (e: SecurityException) { fail("Failed to parse attribute $attr in <$tag> as valid Java class name:" + " ${e.message}") } try { validator.validateResStrAttr(pullParser, index, name) } catch (e: SecurityException) { fail("Failed to parse attribute $attr in <$tag> as valid Java class name:" + " ${e.message}") } } val failNames = arrayOf("com.android.TestClass:", "-TestClass", "TestClass.", ".", "..") for (name in failNames) { val xml = "<$tag $attr=\"$name\" />" pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null) val validator = Validator() pullParser.nextTag() validator.validate(pullParser) val e1 = assertThrows("$name is not valid Java class name", SecurityException::class.java) { validator.validateStrAttr(pullParser, attr, name) } assertEquals(expectedAttrComponentNameErrorMsg(name), e1.message) val e2 = assertThrows("$name is not valid Java class name", SecurityException::class.java) { validator.validateResStrAttr(pullParser, index, name) } assertEquals(expectedAttrComponentNameErrorMsg(name), e2.message) } } private fun validateTagAttr(tag: String, name: String, index: Int?, maxLen: Int) { validateTagAttr_shouldPass(tag, name, index, maxLen) validateTagAttr_shouldFail(tag, name, index, maxLen) Loading Loading @@ -468,4 +524,6 @@ class AndroidPackageParsingValidationTest { fun expectedResAttrLengthErrorMsg(tag: String) = "String length limit exceeded for attribute in $tag" fun expectedAttrComponentNameErrorMsg(name: String) = "$name is not a valid Java class name" } Loading
core/java/android/content/res/Element.java +105 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.os.SystemProperties.PROP_VALUE_MAX; import android.annotation.NonNull; import android.util.Pools.SimplePool; import android.util.Slog; import androidx.annotation.StyleableRes; Loading @@ -41,6 +42,7 @@ public class Element { public static final int MAX_ATTR_LEN_PATH = 4000; public static final int MAX_ATTR_LEN_DATA_VALUE = 4000; private static final String TAG = "PackageParsing"; protected static final String TAG_ACTION = "action"; protected static final String TAG_ACTIVITY = "activity"; protected static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; Loading Loading @@ -715,22 +717,125 @@ public class Element { mChildTagMask |= 1 << idx; } private boolean isComponentNameAttr(String name) { switch (mTag) { case TAG_ACTIVITY: switch (name) { case TAG_ATTR_NAME: case TAG_ATTR_PARENT_ACTIVITY_NAME: return true; default: return false; } case TAG_ACTIVITY_ALIAS: switch (name) { case TAG_ATTR_TARGET_ACTIVITY: return true; default: return false; } case TAG_APPLICATION: switch (name) { case TAG_ATTR_BACKUP_AGENT: case TAG_ATTR_NAME: return true; default: return false; } case TAG_INSTRUMENTATION: case TAG_PROVIDER: case TAG_RECEIVER: case TAG_SERVICE: case TAG_USES_LIBRARY: switch (name) { case TAG_ATTR_NAME: return true; default: return false; } default: return false; } } private boolean isComponentNameAttr(@StyleableRes int index) { switch (mTag) { case TAG_ACTIVITY: return index == R.styleable.AndroidManifestActivity_name || index == R.styleable.AndroidManifestActivity_parentActivityName; case TAG_ACTIVITY_ALIAS: return index == R.styleable.AndroidManifestActivityAlias_targetActivity; case TAG_APPLICATION: return index == R.styleable.AndroidManifestApplication_backupAgent || index == R.styleable.AndroidManifestApplication_name; case TAG_INSTRUMENTATION: return index == R.styleable.AndroidManifestInstrumentation_name; case TAG_PROVIDER: return index == R.styleable.AndroidManifestProvider_name; case TAG_RECEIVER: return index == R.styleable.AndroidManifestReceiver_name; case TAG_SERVICE: return index == R.styleable.AndroidManifestService_name; case TAG_USES_LIBRARY: return index == R.styleable.AndroidManifestUsesLibrary_name; default: return false; } } boolean hasChild(String tag) { return (mChildTagMask & (1 << getCounterIdx(tag))) != 0; } void validateComponentName(CharSequence name) { int i = 0; if (name.charAt(0) == '.') { i = 1; } boolean isStart = true; for (; i < name.length(); i++) { if (name.charAt(i) == '.') { if (isStart) { break; } isStart = true; } else { if (isStart) { if (Character.isJavaIdentifierStart(name.charAt(i))) { isStart = false; } else { break; } } else if (!Character.isJavaIdentifierPart(name.charAt(i))) { break; } } } if ((i < name.length()) || (name.charAt(name.length() - 1) == '.')) { Slog.e(TAG, name + " is not a valid Java class name"); throw new SecurityException(name + " is not a valid Java class name"); } } void validateStrAttr(String attrName, String attrValue) { if (attrValue != null && attrValue.length() > getAttrStrMaxLen(attrName)) { throw new SecurityException("String length limit exceeded for attribute " + attrName + " in " + mTag); } if (isComponentNameAttr(attrName)) { validateComponentName(attrValue); } } void validateResStrAttr(@StyleableRes int index, CharSequence stringValue) { if (stringValue != null && stringValue.length() > getResStrMaxLen(index)) { throw new SecurityException("String length limit exceeded for attribute in " + mTag); } if (isComponentNameAttr(index)) { validateComponentName(stringValue); } } void seen(@NonNull Element element) { TagCounter counter = mTagCounters[getCounterIdx(element.mTag)]; Loading
services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt +59 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,6 @@ class AndroidPackageParsingValidationTest { factory.isNamespaceAware = true factory.newPullParser() } private val ns = "xmlns:android=\"http://schemas.android.com/apk/res/android\"" } @Test Loading Loading @@ -102,9 +101,13 @@ class AndroidPackageParsingValidationTest { val tag = "application" validateTagAttr(tag, "backupAgent", R.styleable.AndroidManifestApplication_backupAgent, 1024) validateTagAttrComponentName(tag, "backupAgent", R.styleable.AndroidManifestApplication_backupAgent) validateTagAttr(tag, "manageSpaceActivity", R.styleable.AndroidManifestApplication_manageSpaceActivity, 1024) validateTagAttr(tag, "name", R.styleable.AndroidManifestApplication_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestApplication_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestApplication_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestApplication_process, 1024) validateTagAttr(tag, "requiredAccountType", Loading Loading @@ -134,6 +137,7 @@ class AndroidPackageParsingValidationTest { fun parseReceiverTag() { val tag = "receiver" validateTagAttr(tag, "name", R.styleable.AndroidManifestReceiver_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestReceiver_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestReceiver_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestReceiver_process, 1024) validateTagCount("meta-data", 1000, tag) Loading @@ -144,6 +148,7 @@ class AndroidPackageParsingValidationTest { fun parseServiceTag() { val tag = "service" validateTagAttr(tag, "name", R.styleable.AndroidManifestService_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestService_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestService_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestService_process, 1024) validateTagCount("meta-data", 1000, tag) Loading @@ -158,6 +163,8 @@ class AndroidPackageParsingValidationTest { R.styleable.AndroidManifestActivityAlias_permission, 1024) validateTagAttr(tag, "targetActivity", R.styleable.AndroidManifestActivityAlias_targetActivity, 1024) validateTagAttrComponentName(tag, "targetActivity", R.styleable.AndroidManifestActivityAlias_targetActivity) validateTagCount("meta-data", 1000, tag) validateTagCount("intent-filter", 20000, tag) } Loading @@ -166,14 +173,18 @@ class AndroidPackageParsingValidationTest { fun parseUsesLibraryTag() { val tag = "uses-library" validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesLibrary_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestUsesLibrary_name) } @Test fun parseActivityTag() { val tag = "activity" validateTagAttr(tag, "name", R.styleable.AndroidManifestActivity_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestActivity_name) validateTagAttr(tag, "parentActivityName", R.styleable.AndroidManifestActivity_parentActivityName, 1024) validateTagAttrComponentName(tag, "parentActivityName", R.styleable.AndroidManifestActivity_parentActivityName) validateTagAttr(tag, "permission", R.styleable.AndroidManifestActivity_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestActivity_process, 1024) validateTagAttr(tag, "taskAffinity", R.styleable.AndroidManifestActivity_taskAffinity, 1024) Loading @@ -200,6 +211,8 @@ class AndroidPackageParsingValidationTest { fun parseInstrumentationTag() { val tag = "instrumentation" validateTagAttr(tag, "name", R.styleable.AndroidManifestInstrumentation_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestInstrumentation_name) validateTagAttr(tag, "targetPackage", R.styleable.AndroidManifestInstrumentation_targetPackage, 256) validateTagAttr(tag, "targetProcesses", Loading Loading @@ -262,6 +275,7 @@ class AndroidPackageParsingValidationTest { fun parseProviderTag() { val tag = "provider" validateTagAttr(tag, "name", R.styleable.AndroidManifestProvider_name, 1024) validateTagAttrComponentName(tag, "name", R.styleable.AndroidManifestProvider_name) validateTagAttr(tag, "permission", R.styleable.AndroidManifestProvider_permission, 1024) validateTagAttr(tag, "process", R.styleable.AndroidManifestProvider_process, 1024) validateTagAttr(tag, "readPermission", Loading Loading @@ -361,6 +375,48 @@ class AndroidPackageParsingValidationTest { validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesPermission_name, 1024) } private fun validateTagAttrComponentName(tag: String, attr: String, index: Int) { val passNames = arrayOf("com.android.TestClass", "TestClass", "_", "$", ".TestClass", "上") for (name in passNames) { val xml = "<$tag $attr=\"$name\" />" pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null) val validator = Validator() pullParser.nextTag() validator.validate(pullParser) try { validator.validateStrAttr(pullParser, attr, name) } catch (e: SecurityException) { fail("Failed to parse attribute $attr in <$tag> as valid Java class name:" + " ${e.message}") } try { validator.validateResStrAttr(pullParser, index, name) } catch (e: SecurityException) { fail("Failed to parse attribute $attr in <$tag> as valid Java class name:" + " ${e.message}") } } val failNames = arrayOf("com.android.TestClass:", "-TestClass", "TestClass.", ".", "..") for (name in failNames) { val xml = "<$tag $attr=\"$name\" />" pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null) val validator = Validator() pullParser.nextTag() validator.validate(pullParser) val e1 = assertThrows("$name is not valid Java class name", SecurityException::class.java) { validator.validateStrAttr(pullParser, attr, name) } assertEquals(expectedAttrComponentNameErrorMsg(name), e1.message) val e2 = assertThrows("$name is not valid Java class name", SecurityException::class.java) { validator.validateResStrAttr(pullParser, index, name) } assertEquals(expectedAttrComponentNameErrorMsg(name), e2.message) } } private fun validateTagAttr(tag: String, name: String, index: Int?, maxLen: Int) { validateTagAttr_shouldPass(tag, name, index, maxLen) validateTagAttr_shouldFail(tag, name, index, maxLen) Loading Loading @@ -468,4 +524,6 @@ class AndroidPackageParsingValidationTest { fun expectedResAttrLengthErrorMsg(tag: String) = "String length limit exceeded for attribute in $tag" fun expectedAttrComponentNameErrorMsg(name: String) = "$name is not a valid Java class name" }