Loading core/java/android/content/res/ApkAssets.java +3 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package android.content.res; import static android.content.res.Resources.ID_NULL; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -386,7 +388,7 @@ public final class ApkAssets { synchronized (this) { long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName); try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) { XmlResourceParser parser = block.newParser(); XmlResourceParser parser = block.newParser(ID_NULL, new Validator()); // If nativeOpenXml doesn't throw, it will always return a valid native pointer, // which makes newParser always return non-null. But let's be careful. if (parser == null) { Loading core/java/android/content/res/AssetManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.content.res; import static android.content.res.Resources.ID_NULL; import android.annotation.AnyRes; import android.annotation.ArrayRes; import android.annotation.AttrRes; Loading Loading @@ -1089,7 +1091,7 @@ public final class AssetManager implements AutoCloseable { public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName) throws IOException { try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) { XmlResourceParser parser = block.newParser(); XmlResourceParser parser = block.newParser(ID_NULL, new Validator()); // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with // a valid native pointer, which makes newParser always return non-null. But let's // be careful. Loading core/java/android/content/res/Element.java 0 → 100644 +405 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.annotation.NonNull; import android.util.ArrayMap; import android.util.Pools.SimplePool; import androidx.annotation.StyleableRes; import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.util.Iterator; import java.util.Map; /** * Defines the string attribute length and child tag count restrictions for a xml element. * * {@hide} */ 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"; protected static final String TAG_ACTION = "action"; protected static final String TAG_ACTIVITY = "activity"; protected static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; protected static final String TAG_ACTIVITY_ALIAS = "activity-alias"; protected static final String TAG_APPLICATION = "application"; protected static final String TAG_ATTRIBUTION = "attribution"; protected static final String TAG_CATEGORY = "category"; protected static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; protected static final String TAG_DATA = "data"; protected static final String TAG_EAT_COMMENT = "eat-comment"; protected static final String TAG_FEATURE_GROUP = "feature-group"; protected static final String TAG_GRANT_URI_PERMISSION = "grant-uri-permission"; protected static final String TAG_INSTRUMENTATION = "instrumentation"; protected static final String TAG_INTENT = "intent"; protected static final String TAG_INTENT_FILTER = "intent-filter"; protected static final String TAG_KEY_SETS = "key-sets"; protected static final String TAG_LAYOUT = "layout"; protected static final String TAG_MANIFEST = "manifest"; protected static final String TAG_META_DATA = "meta-data"; protected static final String TAG_ORIGINAL_PACKAGE = "original-package"; protected static final String TAG_OVERLAY = "overlay"; protected static final String TAG_PACKAGE = "package"; protected static final String TAG_PACKAGE_VERIFIER = "package-verifier"; protected static final String TAG_PATH_PERMISSION = "path-permission"; protected static final String TAG_PERMISSION = "permission"; protected static final String TAG_PERMISSION_GROUP = "permission-group"; protected static final String TAG_PERMISSION_TREE = "permission-tree"; protected static final String TAG_PROFILEABLE = "profileable"; protected static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; protected static final String TAG_PROPERTY = "property"; protected static final String TAG_PROVIDER = "provider"; protected static final String TAG_QUERIES = "queries"; protected static final String TAG_RECEIVER = "receiver"; protected static final String TAG_RESTRICT_UPDATE = "restrict-update"; protected static final String TAG_SCREEN = "screen"; protected static final String TAG_SERVICE = "service"; protected static final String TAG_SUPPORT_SCREENS = "supports-screens"; protected static final String TAG_SUPPORTS_GL_TEXTURE = "supports-gl-texture"; protected static final String TAG_SUPPORTS_INPUT = "supports-input"; protected static final String TAG_SUPPORTS_SCREENS = "supports-screens"; protected static final String TAG_USES_CONFIGURATION = "uses-configuration"; protected static final String TAG_USES_FEATURE = "uses-feature"; protected static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; protected static final String TAG_USES_LIBRARY = "uses-library"; protected static final String TAG_USES_NATIVE_LIBRARY = "uses-native-library"; protected static final String TAG_USES_PERMISSION = "uses-permission"; protected static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; protected static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; protected static final String TAG_USES_SDK = "uses-sdk"; protected static final String TAG_USES_SPLIT = "uses-split"; protected static final String TAG_ATTR_BACKUP_AGENT = "backupAgent"; protected static final String TAG_ATTR_CATEGORY = "category"; protected static final String TAG_ATTR_HOST = "host"; protected static final String TAG_ATTR_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity"; protected static final String TAG_ATTR_MIMETYPE = "mimeType"; protected static final String TAG_ATTR_NAME = "name"; protected static final String TAG_ATTR_PACKAGE = "package"; protected static final String TAG_ATTR_PATH = "path"; protected static final String TAG_ATTR_PATH_ADVANCED_PATTERN = "pathAdvancedPattern"; protected static final String TAG_ATTR_PATH_PATTERN = "pathPattern"; protected static final String TAG_ATTR_PATH_PREFIX = "pathPrefix"; protected static final String TAG_ATTR_PATH_SUFFIX = "pathSuffix"; protected static final String TAG_ATTR_PARENT_ACTIVITY_NAME = "parentActivityName"; protected static final String TAG_ATTR_PERMISSION = "permission"; protected static final String TAG_ATTR_PERMISSION_GROUP = "permissionGroup"; protected static final String TAG_ATTR_PORT = "port"; protected static final String TAG_ATTR_PROCESS = "process"; protected static final String TAG_ATTR_READ_PERMISSION = "readPermission"; protected static final String TAG_ATTR_REQUIRED_ACCOUNT_TYPE = "requiredAccountType"; protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME = "requiredSystemPropertyName"; protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_VALUE = "requiredSystemPropertyValue"; protected static final String TAG_ATTR_RESTRICTED_ACCOUNT_TYPE = "restrictedAccountType"; protected static final String TAG_ATTR_SCHEME = "scheme"; protected static final String TAG_ATTR_SHARED_USER_ID = "sharedUserId"; protected static final String TAG_ATTR_TARGET_ACTIVITY = "targetActivity"; protected static final String TAG_ATTR_TARGET_NAME = "targetName"; protected static final String TAG_ATTR_TARGET_PACKAGE = "targetPackage"; protected static final String TAG_ATTR_TARGET_PROCESSES = "targetProcesses"; protected static final String TAG_ATTR_TASK_AFFINITY = "taskAffinity"; protected static final String TAG_ATTR_VALUE = "value"; 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]; private final Map<String, TagCounter> mTagCounters = new ArrayMap<>(); private String mTag; private static final ThreadLocal<SimplePool<Element>> sPool = ThreadLocal.withInitial(() -> new SimplePool<>(MAX_POOL_SIZE)); @NonNull static Element obtain(@NonNull String tag) { Element element = sPool.get().acquire(); if (element == null) { element = new Element(); } element.init(tag); return element; } void recycle() { mStringAttrNames = new String[0]; Iterator<Map.Entry<String, TagCounter>> it = mTagCounters.entrySet().iterator(); while (it.hasNext()) { it.next().getValue().recycle(); it.remove(); } mTag = null; sPool.get().release(this); } private void init(String tag) { this.mTag = tag; 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); addTagCounter(1000, TAG_LAYOUT); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); break; case TAG_ACTIVITY_ALIAS: setStringAttrNames(ACTIVITY_ALIAS_STR_ATTR_NAMES); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); break; case TAG_APPLICATION: setStringAttrNames(APPLICATION_STR_ATTR_NAMES); addTagCounter(100, TAG_PROFILEABLE); addTagCounter(100, TAG_USES_NATIVE_LIBRARY); addTagCounter(1000, TAG_RECEIVER); addTagCounter(1000, TAG_SERVICE); addTagCounter(4000, TAG_ACTIVITY_ALIAS); addTagCounter(4000, TAG_USES_LIBRARY); addTagCounter(8000, TAG_PROVIDER); addTagCounter(8000, TAG_META_DATA); addTagCounter(40000, TAG_ACTIVITY); break; case TAG_COMPATIBLE_SCREENS: addTagCounter(4000, TAG_SCREEN); 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: addTagCounter(20000, TAG_ACTION); addTagCounter(40000, TAG_CATEGORY); addTagCounter(40000, TAG_DATA); break; case TAG_MANIFEST: setStringAttrNames(MANIFEST_STR_ATTR_NAMES); addTagCounter(100, TAG_APPLICATION); addTagCounter(100, TAG_OVERLAY); addTagCounter(100, TAG_INSTRUMENTATION); addTagCounter(100, TAG_PERMISSION_GROUP); addTagCounter(100, TAG_PERMISSION_TREE); addTagCounter(100, TAG_SUPPORTS_GL_TEXTURE); addTagCounter(100, TAG_SUPPORTS_SCREENS); addTagCounter(100, TAG_USES_CONFIGURATION); addTagCounter(100, TAG_USES_PERMISSION_SDK_23); addTagCounter(100, TAG_USES_SDK); addTagCounter(200, TAG_COMPATIBLE_SCREENS); addTagCounter(200, TAG_QUERIES); addTagCounter(400, TAG_ATTRIBUTION); addTagCounter(400, TAG_USES_FEATURE); addTagCounter(2000, TAG_PERMISSION); addTagCounter(20000, TAG_USES_PERMISSION); 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); addTagCounter(100, TAG_GRANT_URI_PERMISSION); addTagCounter(100, TAG_PATH_PERMISSION); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); break; case TAG_QUERIES: addTagCounter(1000, TAG_PACKAGE); addTagCounter(2000, TAG_INTENT); addTagCounter(8000, TAG_PROVIDER); break; case TAG_RECEIVER: case TAG_SERVICE: setStringAttrNames(RECEIVER_SERVICE_STR_ATTR_NAMES); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); 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) { 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: case TAG_ATTR_SHARED_USER_ID: case TAG_ATTR_TARGET_PACKAGE: return 256; case TAG_ATTR_MIMETYPE: return 512; case TAG_ATTR_BACKUP_AGENT: case TAG_ATTR_CATEGORY: case TAG_ATTR_MANAGE_SPACE_ACTIVITY: case TAG_ATTR_NAME: case TAG_ATTR_PARENT_ACTIVITY_NAME: case TAG_ATTR_PERMISSION: case TAG_ATTR_PROCESS: case TAG_ATTR_READ_PERMISSION: case TAG_ATTR_REQUIRED_ACCOUNT_TYPE: 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_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; default: return DEFAULT_MAX_STRING_ATTR_LENGTH; } } private static int getResStringMaxLength(@StyleableRes int index) { switch (index) { case R.styleable.AndroidManifestData_host: case R.styleable.AndroidManifestData_port: case R.styleable.AndroidManifestData_scheme: return 255; case R.styleable.AndroidManifestData_mimeType: return 512; default: return DEFAULT_MAX_STRING_ATTR_LENGTH; } } private void addTagCounter(int max, String tag) { mTagCounters.put(tag, TagCounter.obtain(max)); } boolean hasChild(String tag) { return mTagCounters.containsKey(tag); } 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 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 seen(@NonNull Element element) throws XmlPullParserException { if (mTagCounters.containsKey(element.mTag)) { TagCounter counter = mTagCounters.get(element.mTag); counter.increment(); if (!counter.isValid()) { throw new XmlPullParserException("The number of child " + element.mTag + " elements exceeded the max allowed in " + this.mTag); } } } } core/java/android/content/res/TagCounter.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.annotation.NonNull; import android.util.Pools.SimplePool; /** * Counter used to track the number of tags seen during manifest validation. * * {@hide} */ public class TagCounter { private static final int MAX_POOL_SIZE = 512; private static final int DEFAULT_MAX_COUNT = 512; private static final ThreadLocal<SimplePool<TagCounter>> sPool = ThreadLocal.withInitial(() -> new SimplePool<>(MAX_POOL_SIZE)); private int mMaxValue; private int mCount; @NonNull static TagCounter obtain(int max) { TagCounter counter = sPool.get().acquire(); if (counter == null) { counter = new TagCounter(); } counter.setMaxValue(max); return counter; } void recycle() { mCount = 0; mMaxValue = DEFAULT_MAX_COUNT; sPool.get().release(this); } public TagCounter() { mMaxValue = DEFAULT_MAX_COUNT; mCount = 0; } private void setMaxValue(int maxValue) { this.mMaxValue = maxValue; } void increment() { mCount += 1; } public boolean isValid() { return mCount <= mMaxValue; } int value() { return mCount; } } core/java/android/content/res/TypedArray.java +11 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ import com.android.internal.util.XmlUtils; import dalvik.system.VMRuntime; import org.xmlpull.v1.XmlPullParserException; import java.util.Arrays; /** Loading Loading @@ -1397,7 +1399,15 @@ public class TypedArray implements AutoCloseable { } return null; } return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]); CharSequence value = mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]); if (mXml != null && mXml.mValidator != null) { try { mXml.mValidator.validateAttr(mXml, index, value); } catch (XmlPullParserException e) { throw new RuntimeException("Failed to validate resource string: " + e.getMessage()); } } return value; } /** @hide */ Loading Loading
core/java/android/content/res/ApkAssets.java +3 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package android.content.res; import static android.content.res.Resources.ID_NULL; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -386,7 +388,7 @@ public final class ApkAssets { synchronized (this) { long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName); try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) { XmlResourceParser parser = block.newParser(); XmlResourceParser parser = block.newParser(ID_NULL, new Validator()); // If nativeOpenXml doesn't throw, it will always return a valid native pointer, // which makes newParser always return non-null. But let's be careful. if (parser == null) { Loading
core/java/android/content/res/AssetManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.content.res; import static android.content.res.Resources.ID_NULL; import android.annotation.AnyRes; import android.annotation.ArrayRes; import android.annotation.AttrRes; Loading Loading @@ -1089,7 +1091,7 @@ public final class AssetManager implements AutoCloseable { public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName) throws IOException { try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) { XmlResourceParser parser = block.newParser(); XmlResourceParser parser = block.newParser(ID_NULL, new Validator()); // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with // a valid native pointer, which makes newParser always return non-null. But let's // be careful. Loading
core/java/android/content/res/Element.java 0 → 100644 +405 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.annotation.NonNull; import android.util.ArrayMap; import android.util.Pools.SimplePool; import androidx.annotation.StyleableRes; import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.util.Iterator; import java.util.Map; /** * Defines the string attribute length and child tag count restrictions for a xml element. * * {@hide} */ 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"; protected static final String TAG_ACTION = "action"; protected static final String TAG_ACTIVITY = "activity"; protected static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; protected static final String TAG_ACTIVITY_ALIAS = "activity-alias"; protected static final String TAG_APPLICATION = "application"; protected static final String TAG_ATTRIBUTION = "attribution"; protected static final String TAG_CATEGORY = "category"; protected static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; protected static final String TAG_DATA = "data"; protected static final String TAG_EAT_COMMENT = "eat-comment"; protected static final String TAG_FEATURE_GROUP = "feature-group"; protected static final String TAG_GRANT_URI_PERMISSION = "grant-uri-permission"; protected static final String TAG_INSTRUMENTATION = "instrumentation"; protected static final String TAG_INTENT = "intent"; protected static final String TAG_INTENT_FILTER = "intent-filter"; protected static final String TAG_KEY_SETS = "key-sets"; protected static final String TAG_LAYOUT = "layout"; protected static final String TAG_MANIFEST = "manifest"; protected static final String TAG_META_DATA = "meta-data"; protected static final String TAG_ORIGINAL_PACKAGE = "original-package"; protected static final String TAG_OVERLAY = "overlay"; protected static final String TAG_PACKAGE = "package"; protected static final String TAG_PACKAGE_VERIFIER = "package-verifier"; protected static final String TAG_PATH_PERMISSION = "path-permission"; protected static final String TAG_PERMISSION = "permission"; protected static final String TAG_PERMISSION_GROUP = "permission-group"; protected static final String TAG_PERMISSION_TREE = "permission-tree"; protected static final String TAG_PROFILEABLE = "profileable"; protected static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; protected static final String TAG_PROPERTY = "property"; protected static final String TAG_PROVIDER = "provider"; protected static final String TAG_QUERIES = "queries"; protected static final String TAG_RECEIVER = "receiver"; protected static final String TAG_RESTRICT_UPDATE = "restrict-update"; protected static final String TAG_SCREEN = "screen"; protected static final String TAG_SERVICE = "service"; protected static final String TAG_SUPPORT_SCREENS = "supports-screens"; protected static final String TAG_SUPPORTS_GL_TEXTURE = "supports-gl-texture"; protected static final String TAG_SUPPORTS_INPUT = "supports-input"; protected static final String TAG_SUPPORTS_SCREENS = "supports-screens"; protected static final String TAG_USES_CONFIGURATION = "uses-configuration"; protected static final String TAG_USES_FEATURE = "uses-feature"; protected static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; protected static final String TAG_USES_LIBRARY = "uses-library"; protected static final String TAG_USES_NATIVE_LIBRARY = "uses-native-library"; protected static final String TAG_USES_PERMISSION = "uses-permission"; protected static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; protected static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; protected static final String TAG_USES_SDK = "uses-sdk"; protected static final String TAG_USES_SPLIT = "uses-split"; protected static final String TAG_ATTR_BACKUP_AGENT = "backupAgent"; protected static final String TAG_ATTR_CATEGORY = "category"; protected static final String TAG_ATTR_HOST = "host"; protected static final String TAG_ATTR_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity"; protected static final String TAG_ATTR_MIMETYPE = "mimeType"; protected static final String TAG_ATTR_NAME = "name"; protected static final String TAG_ATTR_PACKAGE = "package"; protected static final String TAG_ATTR_PATH = "path"; protected static final String TAG_ATTR_PATH_ADVANCED_PATTERN = "pathAdvancedPattern"; protected static final String TAG_ATTR_PATH_PATTERN = "pathPattern"; protected static final String TAG_ATTR_PATH_PREFIX = "pathPrefix"; protected static final String TAG_ATTR_PATH_SUFFIX = "pathSuffix"; protected static final String TAG_ATTR_PARENT_ACTIVITY_NAME = "parentActivityName"; protected static final String TAG_ATTR_PERMISSION = "permission"; protected static final String TAG_ATTR_PERMISSION_GROUP = "permissionGroup"; protected static final String TAG_ATTR_PORT = "port"; protected static final String TAG_ATTR_PROCESS = "process"; protected static final String TAG_ATTR_READ_PERMISSION = "readPermission"; protected static final String TAG_ATTR_REQUIRED_ACCOUNT_TYPE = "requiredAccountType"; protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME = "requiredSystemPropertyName"; protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_VALUE = "requiredSystemPropertyValue"; protected static final String TAG_ATTR_RESTRICTED_ACCOUNT_TYPE = "restrictedAccountType"; protected static final String TAG_ATTR_SCHEME = "scheme"; protected static final String TAG_ATTR_SHARED_USER_ID = "sharedUserId"; protected static final String TAG_ATTR_TARGET_ACTIVITY = "targetActivity"; protected static final String TAG_ATTR_TARGET_NAME = "targetName"; protected static final String TAG_ATTR_TARGET_PACKAGE = "targetPackage"; protected static final String TAG_ATTR_TARGET_PROCESSES = "targetProcesses"; protected static final String TAG_ATTR_TASK_AFFINITY = "taskAffinity"; protected static final String TAG_ATTR_VALUE = "value"; 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]; private final Map<String, TagCounter> mTagCounters = new ArrayMap<>(); private String mTag; private static final ThreadLocal<SimplePool<Element>> sPool = ThreadLocal.withInitial(() -> new SimplePool<>(MAX_POOL_SIZE)); @NonNull static Element obtain(@NonNull String tag) { Element element = sPool.get().acquire(); if (element == null) { element = new Element(); } element.init(tag); return element; } void recycle() { mStringAttrNames = new String[0]; Iterator<Map.Entry<String, TagCounter>> it = mTagCounters.entrySet().iterator(); while (it.hasNext()) { it.next().getValue().recycle(); it.remove(); } mTag = null; sPool.get().release(this); } private void init(String tag) { this.mTag = tag; 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); addTagCounter(1000, TAG_LAYOUT); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); break; case TAG_ACTIVITY_ALIAS: setStringAttrNames(ACTIVITY_ALIAS_STR_ATTR_NAMES); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); break; case TAG_APPLICATION: setStringAttrNames(APPLICATION_STR_ATTR_NAMES); addTagCounter(100, TAG_PROFILEABLE); addTagCounter(100, TAG_USES_NATIVE_LIBRARY); addTagCounter(1000, TAG_RECEIVER); addTagCounter(1000, TAG_SERVICE); addTagCounter(4000, TAG_ACTIVITY_ALIAS); addTagCounter(4000, TAG_USES_LIBRARY); addTagCounter(8000, TAG_PROVIDER); addTagCounter(8000, TAG_META_DATA); addTagCounter(40000, TAG_ACTIVITY); break; case TAG_COMPATIBLE_SCREENS: addTagCounter(4000, TAG_SCREEN); 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: addTagCounter(20000, TAG_ACTION); addTagCounter(40000, TAG_CATEGORY); addTagCounter(40000, TAG_DATA); break; case TAG_MANIFEST: setStringAttrNames(MANIFEST_STR_ATTR_NAMES); addTagCounter(100, TAG_APPLICATION); addTagCounter(100, TAG_OVERLAY); addTagCounter(100, TAG_INSTRUMENTATION); addTagCounter(100, TAG_PERMISSION_GROUP); addTagCounter(100, TAG_PERMISSION_TREE); addTagCounter(100, TAG_SUPPORTS_GL_TEXTURE); addTagCounter(100, TAG_SUPPORTS_SCREENS); addTagCounter(100, TAG_USES_CONFIGURATION); addTagCounter(100, TAG_USES_PERMISSION_SDK_23); addTagCounter(100, TAG_USES_SDK); addTagCounter(200, TAG_COMPATIBLE_SCREENS); addTagCounter(200, TAG_QUERIES); addTagCounter(400, TAG_ATTRIBUTION); addTagCounter(400, TAG_USES_FEATURE); addTagCounter(2000, TAG_PERMISSION); addTagCounter(20000, TAG_USES_PERMISSION); 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); addTagCounter(100, TAG_GRANT_URI_PERMISSION); addTagCounter(100, TAG_PATH_PERMISSION); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); break; case TAG_QUERIES: addTagCounter(1000, TAG_PACKAGE); addTagCounter(2000, TAG_INTENT); addTagCounter(8000, TAG_PROVIDER); break; case TAG_RECEIVER: case TAG_SERVICE: setStringAttrNames(RECEIVER_SERVICE_STR_ATTR_NAMES); addTagCounter(8000, TAG_META_DATA); addTagCounter(20000, TAG_INTENT_FILTER); 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) { 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: case TAG_ATTR_SHARED_USER_ID: case TAG_ATTR_TARGET_PACKAGE: return 256; case TAG_ATTR_MIMETYPE: return 512; case TAG_ATTR_BACKUP_AGENT: case TAG_ATTR_CATEGORY: case TAG_ATTR_MANAGE_SPACE_ACTIVITY: case TAG_ATTR_NAME: case TAG_ATTR_PARENT_ACTIVITY_NAME: case TAG_ATTR_PERMISSION: case TAG_ATTR_PROCESS: case TAG_ATTR_READ_PERMISSION: case TAG_ATTR_REQUIRED_ACCOUNT_TYPE: 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_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; default: return DEFAULT_MAX_STRING_ATTR_LENGTH; } } private static int getResStringMaxLength(@StyleableRes int index) { switch (index) { case R.styleable.AndroidManifestData_host: case R.styleable.AndroidManifestData_port: case R.styleable.AndroidManifestData_scheme: return 255; case R.styleable.AndroidManifestData_mimeType: return 512; default: return DEFAULT_MAX_STRING_ATTR_LENGTH; } } private void addTagCounter(int max, String tag) { mTagCounters.put(tag, TagCounter.obtain(max)); } boolean hasChild(String tag) { return mTagCounters.containsKey(tag); } 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 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 seen(@NonNull Element element) throws XmlPullParserException { if (mTagCounters.containsKey(element.mTag)) { TagCounter counter = mTagCounters.get(element.mTag); counter.increment(); if (!counter.isValid()) { throw new XmlPullParserException("The number of child " + element.mTag + " elements exceeded the max allowed in " + this.mTag); } } } }
core/java/android/content/res/TagCounter.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.annotation.NonNull; import android.util.Pools.SimplePool; /** * Counter used to track the number of tags seen during manifest validation. * * {@hide} */ public class TagCounter { private static final int MAX_POOL_SIZE = 512; private static final int DEFAULT_MAX_COUNT = 512; private static final ThreadLocal<SimplePool<TagCounter>> sPool = ThreadLocal.withInitial(() -> new SimplePool<>(MAX_POOL_SIZE)); private int mMaxValue; private int mCount; @NonNull static TagCounter obtain(int max) { TagCounter counter = sPool.get().acquire(); if (counter == null) { counter = new TagCounter(); } counter.setMaxValue(max); return counter; } void recycle() { mCount = 0; mMaxValue = DEFAULT_MAX_COUNT; sPool.get().release(this); } public TagCounter() { mMaxValue = DEFAULT_MAX_COUNT; mCount = 0; } private void setMaxValue(int maxValue) { this.mMaxValue = maxValue; } void increment() { mCount += 1; } public boolean isValid() { return mCount <= mMaxValue; } int value() { return mCount; } }
core/java/android/content/res/TypedArray.java +11 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ import com.android.internal.util.XmlUtils; import dalvik.system.VMRuntime; import org.xmlpull.v1.XmlPullParserException; import java.util.Arrays; /** Loading Loading @@ -1397,7 +1399,15 @@ public class TypedArray implements AutoCloseable { } return null; } return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]); CharSequence value = mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]); if (mXml != null && mXml.mValidator != null) { try { mXml.mValidator.validateAttr(mXml, index, value); } catch (XmlPullParserException e) { throw new RuntimeException("Failed to validate resource string: " + e.getMessage()); } } return value; } /** @hide */ Loading