Merge "Eliminate redundant attribute reads in validation" into main

This commit is contained in:
William Loh
2023-07-21 19:29:51 +00:00
committed by Android (Google) Code Review
5 changed files with 714 additions and 656 deletions

View File

@@ -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);
}
}

View File

@@ -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());
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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 = "<manifest $ns>"
val suffix = "</manifest>"
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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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 = "</$tag>$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</$parentTag>"
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</$parentTag>"
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 = "<data android:host=\"$host\" />".repeat(2049)
val ns = "http://schemas.android.com/apk/res/android"
val manifestStr = "<manifest xmlns:android=\"$ns\" package=\"test\">$dataTags</manifest>"
parseManifestStr(manifestStr)
val dataTags = "<data host=\"$host\" />".repeat(2049)
val xml = "<manifest package=\"test\">$dataTags</manifest>"
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("<manifest />".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)
}
}
}