diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java index 62a46b6b71525..3e0ab90f99d24 100644 --- a/core/java/android/content/res/Element.java +++ b/core/java/android/content/res/Element.java @@ -16,6 +16,8 @@ package android.content.res; +import static android.os.SystemProperties.PROP_VALUE_MAX; + import android.annotation.NonNull; import android.util.Pools.SimplePool; @@ -23,9 +25,6 @@ import androidx.annotation.StyleableRes; import com.android.internal.R; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - /** * Defines the string attribute length and child tag count restrictions for a xml element. * @@ -34,8 +33,13 @@ import org.xmlpull.v1.XmlPullParserException; public class Element { private static final int DEFAULT_MAX_STRING_ATTR_LENGTH = 32_768; private static final int MAX_POOL_SIZE = 128; - - private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; + private static final int MAX_ATTR_LEN_URL_COMPONENT = 256; + 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_DATA_VALUE = 4000; protected static final String TAG_ACTION = "action"; protected static final String TAG_ACTIVITY = "activity"; @@ -123,43 +127,9 @@ public class Element { protected static final String TAG_ATTR_VERSION_NAME = "versionName"; protected static final String TAG_ATTR_WRITE_PERMISSION = "writePermission"; - private static final String[] ACTIVITY_STR_ATTR_NAMES = {TAG_ATTR_NAME, - TAG_ATTR_PARENT_ACTIVITY_NAME, TAG_ATTR_PERMISSION, TAG_ATTR_PROCESS, - TAG_ATTR_TASK_AFFINITY}; - private static final String[] ACTIVITY_ALIAS_STR_ATTR_NAMES = {TAG_ATTR_NAME, - TAG_ATTR_PERMISSION, TAG_ATTR_TARGET_ACTIVITY}; - private static final String[] APPLICATION_STR_ATTR_NAMES = {TAG_ATTR_BACKUP_AGENT, - TAG_ATTR_MANAGE_SPACE_ACTIVITY, TAG_ATTR_NAME, TAG_ATTR_PERMISSION, TAG_ATTR_PROCESS, - TAG_ATTR_REQUIRED_ACCOUNT_TYPE, TAG_ATTR_RESTRICTED_ACCOUNT_TYPE, - TAG_ATTR_TASK_AFFINITY}; - private static final String[] DATA_STR_ATTR_NAMES = {TAG_ATTR_SCHEME, TAG_ATTR_HOST, - TAG_ATTR_PORT, TAG_ATTR_PATH, TAG_ATTR_PATH_PATTERN, TAG_ATTR_PATH_PREFIX, - TAG_ATTR_PATH_SUFFIX, TAG_ATTR_PATH_ADVANCED_PATTERN, TAG_ATTR_MIMETYPE}; - private static final String[] GRANT_URI_PERMISSION_STR_ATTR_NAMES = {TAG_ATTR_PATH, - TAG_ATTR_PATH_PATTERN, TAG_ATTR_PATH_PREFIX}; - private static final String[] INSTRUMENTATION_STR_ATTR_NAMES = {TAG_ATTR_NAME, - TAG_ATTR_TARGET_PACKAGE, TAG_ATTR_TARGET_PROCESSES}; - private static final String[] MANIFEST_STR_ATTR_NAMES = {TAG_ATTR_PACKAGE, - TAG_ATTR_SHARED_USER_ID, TAG_ATTR_VERSION_NAME}; - private static final String[] OVERLAY_STR_ATTR_NAMES = {TAG_ATTR_CATEGORY, - TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME, TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_VALUE, - TAG_ATTR_TARGET_PACKAGE, TAG_ATTR_TARGET_NAME}; - private static final String[] PATH_PERMISSION_STR_ATTR_NAMES = {TAG_ATTR_PATH, - TAG_ATTR_PATH_PREFIX, TAG_ATTR_PATH_PATTERN, TAG_ATTR_PERMISSION, - TAG_ATTR_READ_PERMISSION, TAG_ATTR_WRITE_PERMISSION}; - private static final String[] PERMISSION_STR_ATTR_NAMES = {TAG_ATTR_NAME, - TAG_ATTR_PERMISSION_GROUP}; - private static final String[] PROVIDER_STR_ATTR_NAMES = {TAG_ATTR_NAME, TAG_ATTR_PERMISSION, - TAG_ATTR_PROCESS, TAG_ATTR_READ_PERMISSION, TAG_ATTR_WRITE_PERMISSION}; - private static final String[] RECEIVER_SERVICE_STR_ATTR_NAMES = {TAG_ATTR_NAME, - TAG_ATTR_PERMISSION, TAG_ATTR_PROCESS}; - private static final String[] NAME_ATTR = {TAG_ATTR_NAME}; - private static final String[] NAME_VALUE_ATTRS = {TAG_ATTR_NAME, TAG_ATTR_VALUE}; - - private String[] mStringAttrNames = new String[0]; // The length of mTagCounters corresponds to the number of tags defined in getCounterIdx. If new // tags are added then the size here should be increased to match. - private final TagCounter[] mTagCounters = new TagCounter[35]; + private final TagCounter[] mTagCounters = new TagCounter[34]; String mTag; @@ -177,7 +147,6 @@ public class Element { } void recycle() { - mStringAttrNames = new String[0]; mTag = null; sPool.get().release(this); } @@ -230,33 +199,79 @@ public class Element { return 20; case TAG_USES_CONFIGURATION: return 21; - case TAG_USES_PERMISSION_SDK_23: - return 22; case TAG_USES_SDK: - return 23; + return 22; case TAG_COMPATIBLE_SCREENS: - return 24; + return 23; case TAG_QUERIES: - return 25; + return 24; case TAG_ATTRIBUTION: - return 26; + return 25; case TAG_USES_FEATURE: - return 27; + return 26; case TAG_PERMISSION: - return 28; + return 27; case TAG_USES_PERMISSION: - return 29; + case TAG_USES_PERMISSION_SDK_23: + case TAG_USES_PERMISSION_SDK_M: + return 28; case TAG_GRANT_URI_PERMISSION: - return 30; + return 29; case TAG_PATH_PERMISSION: - return 31; + return 30; case TAG_PACKAGE: - return 32; + return 31; case TAG_INTENT: - return 33; + return 32; default: // The size of the mTagCounters array should be equal to this value+1 - return 34; + return 33; + } + } + + static boolean shouldValidate(String tag) { + switch (tag) { + case TAG_ACTION: + case TAG_ACTIVITY: + case TAG_ACTIVITY_ALIAS: + case TAG_APPLICATION: + case TAG_ATTRIBUTION: + case TAG_CATEGORY: + case TAG_COMPATIBLE_SCREENS: + case TAG_DATA: + case TAG_GRANT_URI_PERMISSION: + case TAG_INSTRUMENTATION: + case TAG_INTENT: + case TAG_INTENT_FILTER: + case TAG_LAYOUT: + case TAG_MANIFEST: + case TAG_META_DATA: + case TAG_OVERLAY: + case TAG_PACKAGE: + case TAG_PATH_PERMISSION: + case TAG_PERMISSION: + case TAG_PERMISSION_GROUP: + case TAG_PERMISSION_TREE: + case TAG_PROFILEABLE: + case TAG_PROPERTY: + case TAG_PROVIDER: + case TAG_QUERIES: + case TAG_RECEIVER: + case TAG_SCREEN: + case TAG_SERVICE: + case TAG_SUPPORTS_GL_TEXTURE: + case TAG_SUPPORTS_SCREENS: + case TAG_USES_CONFIGURATION: + case TAG_USES_FEATURE: + case TAG_USES_LIBRARY: + case TAG_USES_NATIVE_LIBRARY: + case TAG_USES_PERMISSION: + case TAG_USES_PERMISSION_SDK_23: + case TAG_USES_PERMISSION_SDK_M: + case TAG_USES_SDK: + return true; + default: + return false; } } @@ -264,55 +279,31 @@ public class Element { this.mTag = tag; mChildTagMask = 0; switch (tag) { - case TAG_ACTION: - case TAG_CATEGORY: - case TAG_PACKAGE: - case TAG_PERMISSION_GROUP: - case TAG_PERMISSION_TREE: - case TAG_SUPPORTS_GL_TEXTURE: - case TAG_USES_FEATURE: - case TAG_USES_LIBRARY: - case TAG_USES_NATIVE_LIBRARY: - case TAG_USES_PERMISSION: - case TAG_USES_PERMISSION_SDK_23: - case TAG_USES_SDK: - setStringAttrNames(NAME_ATTR); - break; case TAG_ACTIVITY: - setStringAttrNames(ACTIVITY_STR_ATTR_NAMES); initializeCounter(TAG_LAYOUT, 1000); - initializeCounter(TAG_META_DATA, 8000); + initializeCounter(TAG_META_DATA, 1000); initializeCounter(TAG_INTENT_FILTER, 20000); break; case TAG_ACTIVITY_ALIAS: - setStringAttrNames(ACTIVITY_ALIAS_STR_ATTR_NAMES); - initializeCounter(TAG_META_DATA, 8000); + case TAG_RECEIVER: + case TAG_SERVICE: + initializeCounter(TAG_META_DATA, 1000); initializeCounter(TAG_INTENT_FILTER, 20000); break; case TAG_APPLICATION: - setStringAttrNames(APPLICATION_STR_ATTR_NAMES); initializeCounter(TAG_PROFILEABLE, 100); initializeCounter(TAG_USES_NATIVE_LIBRARY, 100); initializeCounter(TAG_RECEIVER, 1000); initializeCounter(TAG_SERVICE, 1000); + initializeCounter(TAG_META_DATA, 1000); + initializeCounter(TAG_USES_LIBRARY, 1000); initializeCounter(TAG_ACTIVITY_ALIAS, 4000); - initializeCounter(TAG_USES_LIBRARY, 4000); initializeCounter(TAG_PROVIDER, 8000); - initializeCounter(TAG_META_DATA, 8000); initializeCounter(TAG_ACTIVITY, 40000); break; case TAG_COMPATIBLE_SCREENS: initializeCounter(TAG_SCREEN, 4000); break; - case TAG_DATA: - setStringAttrNames(DATA_STR_ATTR_NAMES); - break; - case TAG_GRANT_URI_PERMISSION: - setStringAttrNames(GRANT_URI_PERMISSION_STR_ATTR_NAMES); - break; - case TAG_INSTRUMENTATION: - setStringAttrNames(INSTRUMENTATION_STR_ATTR_NAMES); - break; case TAG_INTENT: case TAG_INTENT_FILTER: initializeCounter(TAG_ACTION, 20000); @@ -320,7 +311,6 @@ public class Element { initializeCounter(TAG_DATA, 40000); break; case TAG_MANIFEST: - setStringAttrNames(MANIFEST_STR_ATTR_NAMES); initializeCounter(TAG_APPLICATION, 100); initializeCounter(TAG_OVERLAY, 100); initializeCounter(TAG_INSTRUMENTATION, 100); @@ -329,7 +319,6 @@ public class Element { initializeCounter(TAG_SUPPORTS_GL_TEXTURE, 100); initializeCounter(TAG_SUPPORTS_SCREENS, 100); initializeCounter(TAG_USES_CONFIGURATION, 100); - initializeCounter(TAG_USES_PERMISSION_SDK_23, 100); initializeCounter(TAG_USES_SDK, 100); initializeCounter(TAG_COMPATIBLE_SCREENS, 200); initializeCounter(TAG_QUERIES, 200); @@ -338,24 +327,10 @@ public class Element { initializeCounter(TAG_PERMISSION, 2000); initializeCounter(TAG_USES_PERMISSION, 20000); break; - case TAG_META_DATA: - case TAG_PROPERTY: - setStringAttrNames(NAME_VALUE_ATTRS); - break; - case TAG_OVERLAY: - setStringAttrNames(OVERLAY_STR_ATTR_NAMES); - break; - case TAG_PATH_PERMISSION: - setStringAttrNames(PATH_PERMISSION_STR_ATTR_NAMES); - break; - case TAG_PERMISSION: - setStringAttrNames(PERMISSION_STR_ATTR_NAMES); - break; case TAG_PROVIDER: - setStringAttrNames(PROVIDER_STR_ATTR_NAMES); initializeCounter(TAG_GRANT_URI_PERMISSION, 100); initializeCounter(TAG_PATH_PERMISSION, 100); - initializeCounter(TAG_META_DATA, 8000); + initializeCounter(TAG_META_DATA, 1000); initializeCounter(TAG_INTENT_FILTER, 20000); break; case TAG_QUERIES: @@ -363,39 +338,23 @@ public class Element { initializeCounter(TAG_INTENT, 2000); initializeCounter(TAG_PROVIDER, 8000); break; - case TAG_RECEIVER: - case TAG_SERVICE: - setStringAttrNames(RECEIVER_SERVICE_STR_ATTR_NAMES); - initializeCounter(TAG_META_DATA, 8000); - initializeCounter(TAG_INTENT_FILTER, 20000); - break; } } - private void setStringAttrNames(String[] attrNames) { - mStringAttrNames = attrNames; - } - - private static String getAttrNamespace(String attrName) { - if (attrName.equals(TAG_ATTR_PACKAGE)) { - return null; - } - return ANDROID_NAMESPACE; - } - - private static int getAttrStringMaxLength(String attrName) { + private static int getAttrStrMaxLen(String attrName) { switch (attrName) { case TAG_ATTR_HOST: - case TAG_ATTR_PACKAGE: - case TAG_ATTR_PERMISSION_GROUP: case TAG_ATTR_PORT: - case TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_VALUE: case TAG_ATTR_SCHEME: + return MAX_ATTR_LEN_URL_COMPONENT; + case TAG_ATTR_PERMISSION_GROUP: + return MAX_ATTR_LEN_PERMISSION_GROUP; case TAG_ATTR_SHARED_USER_ID: + case TAG_ATTR_PACKAGE: case TAG_ATTR_TARGET_PACKAGE: - return 256; + return MAX_ATTR_LEN_PACKAGE; case TAG_ATTR_MIMETYPE: - return 512; + return MAX_ATTR_LEN_MIMETYPE; case TAG_ATTR_BACKUP_AGENT: case TAG_ATTR_CATEGORY: case TAG_ATTR_MANAGE_SPACE_ACTIVITY: @@ -405,33 +364,343 @@ public class Element { case TAG_ATTR_PROCESS: case TAG_ATTR_READ_PERMISSION: case TAG_ATTR_REQUIRED_ACCOUNT_TYPE: + case TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME: case TAG_ATTR_RESTRICTED_ACCOUNT_TYPE: case TAG_ATTR_TARGET_ACTIVITY: case TAG_ATTR_TARGET_NAME: case TAG_ATTR_TARGET_PROCESSES: case TAG_ATTR_TASK_AFFINITY: case TAG_ATTR_WRITE_PERMISSION: - return 1024; + case TAG_ATTR_VERSION_NAME: + return MAX_ATTR_LEN_NAME; case TAG_ATTR_PATH: case TAG_ATTR_PATH_ADVANCED_PATTERN: case TAG_ATTR_PATH_PATTERN: case TAG_ATTR_PATH_PREFIX: case TAG_ATTR_PATH_SUFFIX: - case TAG_ATTR_VERSION_NAME: - return 4000; + return MAX_ATTR_LEN_PATH; + case TAG_ATTR_VALUE: + return MAX_ATTR_LEN_DATA_VALUE; + case TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_VALUE: + return PROP_VALUE_MAX; default: return DEFAULT_MAX_STRING_ATTR_LENGTH; } } - private static int getResStringMaxLength(@StyleableRes int index) { + private int getResStrMaxLen(@StyleableRes int index) { + switch (mTag) { + case TAG_ACTION: + return getActionResStrMaxLen(index); + case TAG_ACTIVITY: + return getActivityResStrMaxLen(index); + case TAG_ACTIVITY_ALIAS: + return getActivityAliasResStrMaxLen(index); + case TAG_APPLICATION: + return getApplicationResStrMaxLen(index); + case TAG_DATA: + return getDataResStrMaxLen(index); + case TAG_CATEGORY: + return getCategoryResStrMaxLen(index); + case TAG_GRANT_URI_PERMISSION: + return getGrantUriPermissionResStrMaxLen(index); + case TAG_INSTRUMENTATION: + return getInstrumentationResStrMaxLen(index); + case TAG_MANIFEST: + return getManifestResStrMaxLen(index); + case TAG_META_DATA: + return getMetaDataResStrMaxLen(index); + case TAG_OVERLAY: + return getOverlayResStrMaxLen(index); + case TAG_PATH_PERMISSION: + return getPathPermissionResStrMaxLen(index); + case TAG_PERMISSION: + return getPermissionResStrMaxLen(index); + case TAG_PERMISSION_GROUP: + return getPermissionGroupResStrMaxLen(index); + case TAG_PERMISSION_TREE: + return getPermissionTreeResStrMaxLen(index); + case TAG_PROPERTY: + return getPropertyResStrMaxLen(index); + case TAG_PROVIDER: + return getProviderResStrMaxLen(index); + case TAG_RECEIVER: + return getReceiverResStrMaxLen(index); + case TAG_SERVICE: + return getServiceResStrMaxLen(index); + case TAG_USES_FEATURE: + return getUsesFeatureResStrMaxLen(index); + case TAG_USES_LIBRARY: + return getUsesLibraryResStrMaxLen(index); + case TAG_USES_NATIVE_LIBRARY: + return getUsesNativeLibraryResStrMaxLen(index); + case TAG_USES_PERMISSION: + case TAG_USES_PERMISSION_SDK_23: + case TAG_USES_PERMISSION_SDK_M: + return getUsesPermissionResStrMaxLen(index); + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getActionResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestAction_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getActivityResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestActivity_name: + case R.styleable.AndroidManifestActivity_parentActivityName: + case R.styleable.AndroidManifestActivity_permission: + case R.styleable.AndroidManifestActivity_process: + case R.styleable.AndroidManifestActivity_taskAffinity: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getActivityAliasResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestActivityAlias_name: + case R.styleable.AndroidManifestActivityAlias_permission: + case R.styleable.AndroidManifestActivityAlias_targetActivity: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getApplicationResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestApplication_backupAgent: + case R.styleable.AndroidManifestApplication_manageSpaceActivity: + case R.styleable.AndroidManifestApplication_name: + case R.styleable.AndroidManifestApplication_permission: + case R.styleable.AndroidManifestApplication_process: + case R.styleable.AndroidManifestApplication_requiredAccountType: + case R.styleable.AndroidManifestApplication_restrictedAccountType: + case R.styleable.AndroidManifestApplication_taskAffinity: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getCategoryResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestCategory_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getDataResStrMaxLen(@StyleableRes int index) { switch (index) { case R.styleable.AndroidManifestData_host: case R.styleable.AndroidManifestData_port: case R.styleable.AndroidManifestData_scheme: - return 255; + return MAX_ATTR_LEN_URL_COMPONENT; case R.styleable.AndroidManifestData_mimeType: - return 512; + return MAX_ATTR_LEN_MIMETYPE; + case R.styleable.AndroidManifestData_path: + case R.styleable.AndroidManifestData_pathPattern: + case R.styleable.AndroidManifestData_pathPrefix: + case R.styleable.AndroidManifestData_pathSuffix: + case R.styleable.AndroidManifestData_pathAdvancedPattern: + return MAX_ATTR_LEN_PATH; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getGrantUriPermissionResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestGrantUriPermission_path: + case R.styleable.AndroidManifestGrantUriPermission_pathPattern: + case R.styleable.AndroidManifestGrantUriPermission_pathPrefix: + return MAX_ATTR_LEN_PATH; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getInstrumentationResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestInstrumentation_targetPackage: + return MAX_ATTR_LEN_PACKAGE; + case R.styleable.AndroidManifestInstrumentation_name: + case R.styleable.AndroidManifestInstrumentation_targetProcesses: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getManifestResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifest_sharedUserId: + return MAX_ATTR_LEN_PACKAGE; + case R.styleable.AndroidManifest_versionName: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getMetaDataResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestMetaData_name: + return MAX_ATTR_LEN_NAME; + case R.styleable.AndroidManifestMetaData_value: + return MAX_ATTR_LEN_DATA_VALUE; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getOverlayResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestResourceOverlay_targetPackage: + return MAX_ATTR_LEN_PACKAGE; + case R.styleable.AndroidManifestResourceOverlay_category: + case R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName: + case R.styleable.AndroidManifestResourceOverlay_targetName: + return MAX_ATTR_LEN_NAME; + case R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue: + return PROP_VALUE_MAX; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getPathPermissionResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestPathPermission_permission: + case R.styleable.AndroidManifestPathPermission_readPermission: + case R.styleable.AndroidManifestPathPermission_writePermission: + return MAX_ATTR_LEN_NAME; + case R.styleable.AndroidManifestPathPermission_path: + case R.styleable.AndroidManifestPathPermission_pathPattern: + case R.styleable.AndroidManifestPathPermission_pathPrefix: + return MAX_ATTR_LEN_PATH; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getPermissionResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestPermission_permissionGroup: + return MAX_ATTR_LEN_PERMISSION_GROUP; + case R.styleable.AndroidManifestPermission_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getPermissionGroupResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestPermissionGroup_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getPermissionTreeResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestPermissionTree_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getPropertyResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestProperty_name: + return MAX_ATTR_LEN_NAME; + case R.styleable.AndroidManifestProperty_value: + return MAX_ATTR_LEN_DATA_VALUE; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getProviderResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestProvider_name: + case R.styleable.AndroidManifestProvider_permission: + case R.styleable.AndroidManifestProvider_process: + case R.styleable.AndroidManifestProvider_readPermission: + case R.styleable.AndroidManifestProvider_writePermission: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getReceiverResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestReceiver_name: + case R.styleable.AndroidManifestReceiver_permission: + case R.styleable.AndroidManifestReceiver_process: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getServiceResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestReceiver_name: + case R.styleable.AndroidManifestReceiver_permission: + case R.styleable.AndroidManifestReceiver_process: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getUsesFeatureResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestUsesFeature_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getUsesLibraryResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestUsesLibrary_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getUsesNativeLibraryResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestUsesNativeLibrary_name: + return MAX_ATTR_LEN_NAME; + default: + return DEFAULT_MAX_STRING_ATTR_LENGTH; + } + } + + private static int getUsesPermissionResStrMaxLen(@StyleableRes int index) { + switch (index) { + case R.styleable.AndroidManifestUsesPermission_name: + return MAX_ATTR_LEN_NAME; default: return DEFAULT_MAX_STRING_ATTR_LENGTH; } @@ -450,31 +719,25 @@ public class Element { return (mChildTagMask & (1 << getCounterIdx(tag))) != 0; } - void validateStringAttrs(@NonNull XmlPullParser attrs) throws XmlPullParserException { - for (int i = 0; i < mStringAttrNames.length; i++) { - String attrName = mStringAttrNames[i]; - String val = attrs.getAttributeValue(getAttrNamespace(attrName), attrName); - if (val != null && val.length() > getAttrStringMaxLength(attrName)) { - throw new XmlPullParserException("String length limit exceeded for " - + "attribute " + attrName + " in " + mTag); - } + 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); } } - void validateResStringAttr(@StyleableRes int index, CharSequence stringValue) - throws XmlPullParserException { - if (stringValue != null && stringValue.length() > getResStringMaxLength(index)) { - throw new XmlPullParserException("String length limit exceeded for " - + "attribute in " + mTag); + 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); } } - void seen(@NonNull Element element) throws XmlPullParserException { + void seen(@NonNull Element element) { TagCounter counter = mTagCounters[getCounterIdx(element.mTag)]; if (counter != null) { counter.increment(); if (!counter.isValid()) { - throw new XmlPullParserException("The number of child " + element.mTag + throw new SecurityException("The number of child " + element.mTag + " elements exceeded the max allowed in " + this.mTag); } } diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 2e84636202be5..48adfb907ab4d 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -1393,16 +1393,17 @@ public class TypedArray implements AutoCloseable { private CharSequence loadStringValueAt(int index) { final int[] data = mData; final int cookie = data[index + STYLE_ASSET_COOKIE]; + CharSequence value = null; if (cookie < 0) { if (mXml != null) { - return mXml.getPooledString(data[index + STYLE_DATA]); + value = mXml.getPooledString(data[index + STYLE_DATA]); } - return null; + } else { + value = mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]); } - CharSequence value = mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]); - if (mXml != null && mXml.mValidator != null) { + if (value != null && mXml != null && mXml.mValidator != null) { try { - mXml.mValidator.validateAttr(mXml, index, value); + mXml.mValidator.validateResStrAttr(mXml, index / STYLE_NUM_ENTRIES, value); } catch (XmlPullParserException e) { throw new RuntimeException("Failed to validate resource string: " + e.getMessage()); } diff --git a/core/java/android/content/res/Validator.java b/core/java/android/content/res/Validator.java index 8b5e6c61d3045..cae353b3bd5ae 100644 --- a/core/java/android/content/res/Validator.java +++ b/core/java/android/content/res/Validator.java @@ -16,9 +16,8 @@ package android.content.res; -import static android.content.res.Element.TAG_MANIFEST; - import android.annotation.NonNull; +import android.annotation.StyleableRes; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -55,24 +54,19 @@ public class Validator { return; } if (eventType == XmlPullParser.START_TAG) { - try { - String tag = parser.getName(); - // only validate manifests - if (depth == 0 && mElements.size() == 0 && !TAG_MANIFEST.equals(tag)) { - return; - } + String tag = parser.getName(); + if (Element.shouldValidate(tag)) { + Element element = Element.obtain(tag); Element parent = mElements.peek(); - if (parent == null || parent.hasChild(tag)) { - Element element = Element.obtain(tag); - element.validateStringAttrs(parser); - if (parent != null) { + if (parent != null && parent.hasChild(tag)) { + try { parent.seen(element); + } catch (SecurityException e) { + cleanUp(); + throw e; } - mElements.push(element); } - } catch (XmlPullParserException e) { - cleanUp(); - throw e; + mElements.push(element); } } else if (eventType == XmlPullParser.END_TAG && depth == mElements.size()) { mElements.pop().recycle(); @@ -84,11 +78,21 @@ public class Validator { /** * Validates the resource string of a manifest tag attribute. */ - public void validateAttr(@NonNull XmlPullParser parser, int index, CharSequence stringValue) - throws XmlPullParserException { + public void validateResStrAttr(@NonNull XmlPullParser parser, @StyleableRes int index, + CharSequence stringValue) throws XmlPullParserException { if (parser.getDepth() > mElements.size()) { return; } - mElements.peek().validateResStringAttr(index, stringValue); + mElements.peek().validateResStrAttr(index, stringValue); + } + + /** + * Validates the string of a manifest tag attribute by name. + */ + public void validateStrAttr(@NonNull XmlPullParser parser, String attrName, String attrValue) { + if (parser.getDepth() > mElements.size()) { + return; + } + mElements.peek().validateStrAttr(attrName, attrValue); } } diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index 3afc830fa14d3..7649b32a6c7ad 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -319,7 +319,11 @@ public final class XmlBlock implements AutoCloseable { "Namespace=" + getAttributeNamespace(idx) + "Name=" + getAttributeName(idx) + ", Value=" + getAttributeValue(idx)); - return getAttributeValue(idx); + String value = getAttributeValue(idx); + if (mValidator != null) { + mValidator.validateStrAttr(this, name, value); + } + return value; } return null; } diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt index 003797066b392..8c07b6cbc894e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt @@ -18,6 +18,7 @@ package com.android.server.pm.parsing import android.content.res.Validator import android.os.Environment +import android.os.SystemProperties.PROP_VALUE_MAX import android.platform.test.annotations.Postsubmit import com.android.internal.R import com.android.server.pm.PackageManagerService @@ -28,7 +29,6 @@ import org.junit.Assert.assertThrows import org.junit.Assert.fail import org.junit.Test import org.xmlpull.v1.XmlPullParser -import org.xmlpull.v1.XmlPullParserException import org.xmlpull.v1.XmlPullParserFactory import java.io.ByteArrayInputStream import java.io.File @@ -75,548 +75,370 @@ class AndroidPackageParsingValidationTest { } @Test - fun parseBadManifests() { + fun parseManifestTag() { val tag = "manifest" - val prefix = "" - val suffix = "" - parseTagBadAttr(tag, "package", 256, ) - parseTagBadAttr(tag, "android:sharedUserId", 256) - parseTagBadAttr(tag, "android:versionName", 4000) - parseBadApplicationTags(100, prefix, suffix, tag) - parseBadOverlayTags(100, prefix, suffix, tag) - parseBadInstrumentationTags(100, prefix, suffix, tag) - parseBadPermissionGroupTags(100, prefix, suffix, tag) - parseBadPermissionTreeTags(100, prefix, suffix, tag) - parseBadSupportsGlTextureTags(100, prefix, suffix, tag) - parseBadSupportsScreensTags(100, prefix, suffix, tag) - parseBadUsesConfigurationTags(100, prefix, suffix, tag) - parseBadUsesPermissionSdk23Tags(100, prefix, suffix, tag) - parseBadUsesSdkTags(100, prefix, suffix, tag) - parseBadCompatibleScreensTags(200, prefix, suffix, tag) - parseBadQueriesTags(200, prefix, suffix, tag) - parseBadAttributionTags(400, prefix, suffix, tag) - parseBadUsesFeatureTags(400, prefix, suffix, tag) - parseBadPermissionTags(2000, prefix, suffix, tag) - parseBadUsesPermissionTags(20000, prefix, suffix, tag) + validateTagAttr(tag, "package", null, 256) + validateTagAttr(tag, "sharedUserId", null, 256) + validateTagAttr(tag, "versionName", null, 1024) + validateTagCount("application", 100, tag) + validateTagCount("overlay", 100, tag) + validateTagCount("instrumentation", 100, tag) + validateTagCount("permission-group", 100, tag) + validateTagCount("permission-tree", 100, tag) + validateTagCount("supports-gl-texture", 100, tag) + validateTagCount("supports-screens", 100, tag) + validateTagCount("uses-configuration", 100, tag) + validateTagCount("uses-sdk", 100, tag) + validateTagCount("compatible-screens", 200, tag) + validateTagCount("queries", 200, tag) + validateTagCount("attribution", 400, tag) + validateTagCount("uses-feature", 400, tag) + validateTagCount("permission", 2000, tag) + validateTagCount("uses-permission", 20000, tag) } - private fun parseBadApplicationTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseApplicationTag() { val tag = "application" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - - parseTagBadAttr(tag, "android:backupAgent", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:manageSpaceActivity", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:process", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:requiredAccountType", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:restrictedAccountType", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:taskAffinity", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - - parseBadProfileableTags(100, newPrefix, newSuffix, tag) - parseBadUsesNativeLibraryTags(100, newPrefix, newSuffix, tag) - parseBadReceiverTags(1000, newPrefix, newSuffix, tag) - parseBadServiceTags(1000, newPrefix, newSuffix, tag) - parseBadActivityAliasTags(4000, newPrefix, newSuffix, tag) - parseBadUsesLibraryTags(4000, newPrefix, newSuffix, tag) - parseBadProviderTags(8000, newPrefix, newSuffix, tag) - parseBadMetaDataTags(8000, newPrefix, newSuffix, tag) - parseBadActivityTags(40000, newPrefix, newSuffix, tag) + validateTagAttr(tag, "backupAgent", + R.styleable.AndroidManifestApplication_backupAgent, 1024) + validateTagAttr(tag, "manageSpaceActivity", + R.styleable.AndroidManifestApplication_manageSpaceActivity, 1024) + validateTagAttr(tag, "name", R.styleable.AndroidManifestApplication_name, 1024) + validateTagAttr(tag, "permission", R.styleable.AndroidManifestApplication_permission, 1024) + validateTagAttr(tag, "process", R.styleable.AndroidManifestApplication_process, 1024) + validateTagAttr(tag, "requiredAccountType", + R.styleable.AndroidManifestApplication_requiredAccountType, 1024) + validateTagAttr(tag, "restrictedAccountType", + R.styleable.AndroidManifestApplication_restrictedAccountType, 1024) + validateTagAttr(tag, "taskAffinity", + R.styleable.AndroidManifestApplication_taskAffinity, 1024) + validateTagCount("profileable", 100, tag) + validateTagCount("uses-native-library", 100, tag) + validateTagCount("receiver", 1000, tag) + validateTagCount("service", 1000, tag) + validateTagCount("meta-data", 1000, tag) + validateTagCount("uses-library", 1000, tag) + validateTagCount("activity-alias", 4000, tag) + validateTagCount("provider", 8000, tag) + validateTagCount("activity", 40000, tag) } - private fun parseBadProfileableTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "profileable" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadUsesNativeLibraryTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseUsesNativeLibraryTag() { val tag = "uses-native-library" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesNativeLibrary_name, 1024) } - private fun parseBadReceiverTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseReceiverTag() { val tag = "receiver" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:process", 1024, prefix, suffix) - - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadMetaDataTags(8000, newPrefix, newSuffix, tag) - parseBadIntentFilterTags(20000, newPrefix, newSuffix, tag) + validateTagAttr(tag, "name", R.styleable.AndroidManifestReceiver_name, 1024) + validateTagAttr(tag, "permission", R.styleable.AndroidManifestReceiver_permission, 1024) + validateTagAttr(tag, "process", R.styleable.AndroidManifestReceiver_process, 1024) + validateTagCount("meta-data", 1000, tag) + validateTagCount("intent-filter", 20000, tag) } - private fun parseBadServiceTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseServiceTag() { val tag = "service" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:process", 1024, prefix, suffix) - - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadMetaDataTags(8000, newPrefix, newSuffix, tag) - parseBadIntentFilterTags(20000, newPrefix, newSuffix, tag) + validateTagAttr(tag, "name", R.styleable.AndroidManifestService_name, 1024) + validateTagAttr(tag, "permission", R.styleable.AndroidManifestService_permission, 1024) + validateTagAttr(tag, "process", R.styleable.AndroidManifestService_process, 1024) + validateTagCount("meta-data", 1000, tag) + validateTagCount("intent-filter", 20000, tag) } - private fun parseBadActivityAliasTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseActivityAliasTag() { val tag = "activity-alias" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:targetActivity", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadMetaDataTags(8000, newPrefix, newSuffix, tag) - parseBadIntentFilterTags(20000, newPrefix, newSuffix, tag) + validateTagAttr(tag, "name", R.styleable.AndroidManifestActivityAlias_name, 1024) + validateTagAttr(tag, "permission", + R.styleable.AndroidManifestActivityAlias_permission, 1024) + validateTagAttr(tag, "targetActivity", + R.styleable.AndroidManifestActivityAlias_targetActivity, 1024) + validateTagCount("meta-data", 1000, tag) + validateTagCount("intent-filter", 20000, tag) } - private fun parseBadUsesLibraryTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseUsesLibraryTag() { val tag = "uses-library" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesLibrary_name, 1024) } - private fun parseBadActivityTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseActivityTag() { val tag = "activity" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:parentActivityName", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:process", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:taskAffinity", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadLayoutTags(1000, newPrefix, newSuffix, tag) - parseBadMetaDataTags(8000, newPrefix, newSuffix, tag) - parseBadIntentFilterTags(20000, newPrefix, newSuffix, tag) + validateTagAttr(tag, "name", R.styleable.AndroidManifestActivity_name, 1024) + validateTagAttr(tag, "parentActivityName", + R.styleable.AndroidManifestActivity_parentActivityName, 1024) + validateTagAttr(tag, "permission", R.styleable.AndroidManifestActivity_permission, 1024) + validateTagAttr(tag, "process", R.styleable.AndroidManifestActivity_process, 1024) + validateTagAttr(tag, "taskAffinity", R.styleable.AndroidManifestActivity_taskAffinity, 1024) + validateTagCount("layout", 1000, tag) + validateTagCount("meta-data", 1000, tag) + validateTagCount("intent-filter", 20000, tag) } - private fun parseBadLayoutTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "layout" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadOverlayTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseOverlayTag() { val tag = "overlay" - parseTagBadAttr(tag, "android:category", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:requiredSystemPropertyName", 32768, prefix, suffix) - parseTagBadAttr(tag, "android:requiredSystemPropertyValue", 256, prefix, suffix) - parseTagBadAttr(tag, "android:targetPackage", 256, prefix, suffix) - parseTagBadAttr(tag, "android:targetName", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "category", R.styleable.AndroidManifestResourceOverlay_category, 1024) + validateTagAttr(tag, "requiredSystemPropertyName", + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName, 1024) + validateTagAttr(tag, "requiredSystemPropertyValue", + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue, PROP_VALUE_MAX) + validateTagAttr(tag, "targetPackage", + R.styleable.AndroidManifestResourceOverlay_targetPackage, 256) + validateTagAttr(tag, "targetName", + R.styleable.AndroidManifestResourceOverlay_targetName, 1024) } - private fun parseBadInstrumentationTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseInstrumentationTag() { val tag = "instrumentation" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:targetPackage", 256, prefix, suffix) - parseTagBadAttr(tag, "android:targetProcesses", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestInstrumentation_name, 1024) + validateTagAttr(tag, "targetPackage", + R.styleable.AndroidManifestInstrumentation_targetPackage, 256) + validateTagAttr(tag, "targetProcesses", + R.styleable.AndroidManifestInstrumentation_targetProcesses, 1024) } - private fun parseBadPermissionGroupTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parsePermissionGroupTag() { val tag = "permission-group" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestPermissionGroup_name, 1024) } - private fun parseBadPermissionTreeTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parsePermissionTreeTag() { val tag = "permission-tree" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestPermissionTree_name, 1024) } - private fun parseBadSupportsGlTextureTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseSupportsGlTextureTag() { val tag = "supports-gl-texture" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", null, 1024) } - private fun parseBadSupportsScreensTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "supports-screens" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadUsesConfigurationTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "uses-configuration" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadUsesPermissionSdk23Tags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseUsesPermissionSdk23Tag() { val tag = "uses-permission-sdk-23" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesPermission_name, 1024) } - private fun parseBadUsesSdkTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "uses-sdk" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadCompatibleScreensTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseCompatibleScreensTag() { val tag = "compatible-screens" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadScreenTags(4000, newPrefix, newSuffix, tag) + validateTagCount("screen", 4000, tag) } - private fun parseBadScreenTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "screen" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadQueriesTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseQueriesTag() { val tag = "queries" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadPackageTags(1000, newPrefix, newSuffix, tag) - parseBadIntentTags(2000, newPrefix, newSuffix, tag) - parseBadProviderTags(8000, newPrefix, newSuffix, tag) + validateTagCount("package", 1000, tag) + validateTagCount("intent", 2000, tag) + validateTagCount("provider", 8000, tag) } - private fun parseBadPackageTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parsePackageTag() { val tag = "package" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", null, 1024) } - private fun parseBadIntentTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseIntentTag() { val tag = "intent" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadActionTags(20000, newPrefix, newSuffix, tag) - parseBadCategoryTags(40000, newPrefix, newSuffix, tag) - parseBadDataTags(40000, newPrefix, newSuffix, tag) + validateTagCount("action", 20000, tag) + validateTagCount("category", 40000, tag) + validateTagCount("data", 40000, tag) } - private fun parseBadProviderTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseProviderTag() { val tag = "provider" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:process", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:readPermission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:writePermission", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadGrantUriPermissionTags(100, newPrefix, newSuffix, tag) - parseBadPathPermissionTags(100, newPrefix, newSuffix, tag) - parseBadMetaDataTags(8000, newPrefix, newSuffix, tag) - parseBadIntentFilterTags(20000, newPrefix, newSuffix, tag) + validateTagAttr(tag, "name", R.styleable.AndroidManifestProvider_name, 1024) + validateTagAttr(tag, "permission", R.styleable.AndroidManifestProvider_permission, 1024) + validateTagAttr(tag, "process", R.styleable.AndroidManifestProvider_process, 1024) + validateTagAttr(tag, "readPermission", + R.styleable.AndroidManifestProvider_readPermission, 1024) + validateTagAttr(tag, "writePermission", + R.styleable.AndroidManifestProvider_writePermission, 1024) + validateTagCount("grant-uri-permission", 100, tag) + validateTagCount("path-permission", 100, tag) + validateTagCount("meta-data", 1000, tag) + validateTagCount("intent-filter", 20000, tag) } - private fun parseBadGrantUriPermissionTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseGrantUriPermissionTag() { val tag = "grant-uri-permission" - parseTagBadAttr(tag, "android:path", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathPrefix", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathPattern", 4000, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "path", R.styleable.AndroidManifestGrantUriPermission_path, 4000) + validateTagAttr(tag, "pathPrefix", + R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 4000) + validateTagAttr(tag, "pathPattern", + R.styleable.AndroidManifestGrantUriPermission_pathPattern, 4000) } - private fun parseBadPathPermissionTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parsePathPermissionTag() { val tag = "path-permission" - parseTagBadAttr(tag, "android:path", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathPrefix", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathPattern", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:permission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:readPermission", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:writePermission", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "path", R.styleable.AndroidManifestPathPermission_path, 4000) + validateTagAttr(tag, "pathPrefix", + R.styleable.AndroidManifestPathPermission_pathPrefix, 4000) + validateTagAttr(tag, "pathPattern", + R.styleable.AndroidManifestPathPermission_pathPattern, 4000) + validateTagAttr(tag, "permission", + R.styleable.AndroidManifestPathPermission_permission, 1024) + validateTagAttr(tag, "readPermission", + R.styleable.AndroidManifestPathPermission_readPermission, 1024) + validateTagAttr(tag, "writePermission", + R.styleable.AndroidManifestPathPermission_writePermission, 1024) } - private fun parseBadMetaDataTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseMetaDataTag() { val tag = "meta-data" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:value", 32768, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestMetaData_name, 1024) + validateTagAttr(tag, "value", R.styleable.AndroidManifestMetaData_value, 4000) } - private fun parseBadIntentFilterTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseIntentFilterTag() { val tag = "intent-filter" - val newPrefix = "$prefix<$tag>" - val newSuffix = "$suffix" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - parseBadActionTags(20000, newPrefix, newSuffix, tag) - parseBadCategoryTags(40000, newPrefix, newSuffix, tag) - parseBadDataTags(40000, newPrefix, newSuffix, tag) + validateTagCount("action", 20000, tag) + validateTagCount("category", 40000, tag) + validateTagCount("data", 40000, tag) } - private fun parseBadActionTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseActionTag() { val tag = "action" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestAction_name, 1024) } - private fun parseBadCategoryTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseCategoryTag() { val tag = "category" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestCategory_name, 1024) } - private fun parseBadDataTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseDataTag() { val tag = "data" - parseTagBadAttr(tag, "android:scheme", 256, prefix, suffix) - parseTagBadAttr(tag, "android:host", 256, prefix, suffix) - parseTagBadAttr(tag, "android:path", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathPattern", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathPrefix", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathSuffix", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:pathAdvancedPattern", 4000, prefix, suffix) - parseTagBadAttr(tag, "android:mimeType", 512, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "scheme", R.styleable.AndroidManifestData_scheme, 256) + validateTagAttr(tag, "host", R.styleable.AndroidManifestData_host, 256) + validateTagAttr(tag, "path", R.styleable.AndroidManifestData_path, 4000) + validateTagAttr(tag, "pathPattern", R.styleable.AndroidManifestData_pathPattern, 4000) + validateTagAttr(tag, "pathPrefix", R.styleable.AndroidManifestData_pathPrefix, 4000) + validateTagAttr(tag, "pathSuffix", R.styleable.AndroidManifestData_pathSuffix, 4000) + validateTagAttr(tag, "pathAdvancedPattern", + R.styleable.AndroidManifestData_pathAdvancedPattern, 4000) + validateTagAttr(tag, "mimeType", R.styleable.AndroidManifestData_mimeType, 512) } - private fun parseBadAttributionTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { - val tag = "attribution" - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) - } - - private fun parseBadUsesFeatureTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseUsesFeatureTag() { val tag = "uses-feature" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesFeature_name, 1024) } - private fun parseBadPermissionTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parsePermissionTag() { val tag = "permission" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseTagBadAttr(tag, "android:permissionGroup", 256, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestPermission_name, 1024) + validateTagAttr(tag, "permissionGroup", + R.styleable.AndroidManifestPermission_permissionGroup, 256) } - private fun parseBadUsesPermissionTags( - maxNum: Int, - prefix: String, - suffix: String, - parentTag: String - ) { + @Test + fun parseUsesPermissionTag() { val tag = "uses-permission" - parseTagBadAttr(tag, "android:name", 1024, prefix, suffix) - parseBadTagCount(tag, maxNum, parentTag, prefix, suffix) + validateTagAttr(tag, "name", R.styleable.AndroidManifestUsesPermission_name, 1024) } - private fun parseTagBadAttr( - tag: String, - attrName: String, - maxLength: Int, - prefix: String = "", - suffix: String = "" + private fun validateTagAttr(tag: String, name: String, index: Int?, maxLen: Int) { + validateTagAttr_shouldPass(tag, name, index, maxLen) + validateTagAttr_shouldFail(tag, name, index, maxLen) + } + + private fun validateTagAttr_shouldPass( + tag: String, + name: String, + index: Int?, + maxLen: Int ) { - var attrValue = "x".repeat(maxLength) - var tagValue = if (tag.equals("manifest")) "$tag $ns" else tag - var manifestStr = "$prefix<$tagValue $attrName=\"$attrValue\" />$suffix" + val value = "x".repeat(maxLen) + val xml = "<$tag $name=\"$value\" />" + pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null) + val validator = Validator() + pullParser.nextTag() + validator.validate(pullParser) try { - parseManifestStr(manifestStr) - } catch (e: XmlPullParserException) { - fail("Failed to parse valid <$tag> attribute $attrName with max length of $maxLength:" + + validator.validateStrAttr(pullParser, name, value) + } catch (e: SecurityException) { + fail("Failed to parse valid <$tag> attribute $name with max length of $maxLen:" + " ${e.message}") } - attrValue = "x".repeat(maxLength + 1) - manifestStr = "$prefix<$tagValue $attrName=\"$attrValue\" />$suffix" - val e = assertThrows(XmlPullParserException::class.java) { - parseManifestStr(manifestStr) + if (index != null) { + try { + validator.validateResStrAttr(pullParser, index, value) + } catch (e: SecurityException) { + fail("Failed to parse valid <$tag> resource string attribute $name with max" + + " length of $maxLen: ${e.message}") + } } - assertEquals(expectedAttrLengthErrorMsg(attrName.split(":").last(), tag), e.message) } - private fun parseBadTagCount( - tag: String, - maxNum: Int, - parentTag: String, - prefix: String, - suffix: String + private fun validateTagAttr_shouldFail( + tag: String, + name: String, + index: Int?, + maxLen: Int ) { - var tags = "<$tag />".repeat(maxNum) - var manifestStr = "$prefix$tags$suffix" + val value = "x".repeat(maxLen + 1) + val xml = "<$tag $name=\"$value\" />" + pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null) + val validator = Validator() + pullParser.nextTag() + validator.validate(pullParser) + val e1 = assertThrows(SecurityException::class.java) { + validator.validateStrAttr(pullParser, name, value) + } + assertEquals(expectedAttrLengthErrorMsg(name, tag), e1.message) + if (index != null) { + val e2 = assertThrows(SecurityException::class.java) { + validator.validateResStrAttr(pullParser, index, value) + } + assertEquals(expectedResAttrLengthErrorMsg(tag), e2.message) + } + } + + private fun validateTagCount(tag: String, maxNum: Int, parentTag: String) { + validateTagCount_shouldPass(tag, maxNum, parentTag) + validateTagCount_shouldFail(tag, maxNum, parentTag) + } + + private fun validateTagCount_shouldPass(tag: String, maxNum: Int, parentTag: String) { + val tags = "<$tag />".repeat(maxNum) + val xml = "<$parentTag>$tags" try { - parseManifestStr(manifestStr) - } catch (e: XmlPullParserException) { + parseXmlStr(xml) + } catch (e: SecurityException) { fail("Failed to parse <$tag> with max count limit of $maxNum under" + " <$parentTag>: ${e.message}") } - tags = "<$tag />".repeat(maxNum + 1) - manifestStr = "$prefix$tags$suffix" - val e = assertThrows(XmlPullParserException::class.java) { - parseManifestStr(manifestStr) + } + + private fun validateTagCount_shouldFail(tag: String, maxNum: Int, parentTag: String) { + val tags = "<$tag />".repeat(maxNum + 1) + val xml = "<$parentTag>$tags" + val e = assertThrows(SecurityException::class.java) { + parseXmlStr(xml) } assertEquals(expectedCountErrorMsg(tag, parentTag), e.message) } @@ -624,13 +446,12 @@ class AndroidPackageParsingValidationTest { @Test fun parseUnexpectedTag_shouldSkip() { val host = "x".repeat(256) - val dataTags = "".repeat(2049) - val ns = "http://schemas.android.com/apk/res/android" - val manifestStr = "$dataTags" - parseManifestStr(manifestStr) + val dataTags = "".repeat(2049) + val xml = "$dataTags" + parseXmlStr(xml) } - fun parseManifestStr(manifestStr: String) { + fun parseXmlStr(manifestStr: String) { pullParser.setInput(ByteArrayInputStream(manifestStr.toByteArray()), null) val validator = Validator() do { @@ -647,39 +468,4 @@ class AndroidPackageParsingValidationTest { fun expectedResAttrLengthErrorMsg(tag: String) = "String length limit exceeded for attribute in $tag" - - @Test - fun validateResAttrs() { - pullParser.setInput(ByteArrayInputStream("".toByteArray()), null) - pullParser.next() - val validator = Validator() - validator.validate(pullParser) - validateResAttr(pullParser, validator, R.styleable.AndroidManifestData_host, - "R.styleable.AndroidManifestData_host", 255) - validateResAttr(pullParser, validator, R.styleable.AndroidManifestData_port, - "R.styleable.AndroidManifestData_port", 255) - validateResAttr(pullParser, validator, R.styleable.AndroidManifestData_scheme, - "R.styleable.AndroidManifestData_scheme", 255) - validateResAttr(pullParser, validator, R.styleable.AndroidManifestData_mimeType, - "R.styleable.AndroidManifestData_mimeType", 512) - } - - fun validateResAttr( - parser: XmlPullParser, - validator: Validator, - resId: Int, - resIdStr: String, - maxLength: Int - ) { - try { - validator.validateAttr(parser, resId, "x".repeat(maxLength)) - } catch (e: XmlPullParserException) { - fail("Failed to parse valid string resource attribute $resIdStr with max length of" + - " $maxLength: ${e.message}") - } - val e = assertThrows(XmlPullParserException::class.java) { - validator.validateAttr(parser, resId, "x".repeat(maxLength + 1)) - } - assertEquals(expectedResAttrLengthErrorMsg("manifest"), e.message) - } -} \ No newline at end of file +}