CVE-2025-48644 AI-generated analysis
platform/frameworks/base, input method framework (android.view.inputmethod.InputMethodInfo, com.android.internal.inputmethod, InputMethodManagerService)
Caps the cumulative size of resolved InputMethodInfo metadata attributes at MAX_METADATA_SIZE_BYTES via a TypedArrayWrapper/MetadataReadBytesTracker in the InputMethodInfo constructor, and moves the IInputMethodManager list-returning IPCs (getInputMethodList, getEnabledInputMethodList, getEnabledInputMethodSubtypeList) to blob-backed InputMethodInfoSafeList/InputMethodSubtypeSafeList parcelables to avoid oversized Binder transactions.
Root cause
The InputMethodInfo constructor parses an IME's <input-method> XML metadata with res.obtainAttributes() and TypedArray.getString()/getBoolean()/getInt()/getResourceId(). The only size checks were a validation of the raw XML file size (the InputStream.skip() loop) and a 1000-char COMPONENT_NAME_MAX_LENGTH check on si.name and settingsActivity. String attributes may be resource references (e.g. @string/...) whose resolved value is much larger than the XML file. Per the commit messages, this can lead to OOM during parsing or to large Binder transactions (TransactionTooLargeException) when List<InputMethodInfo> / List<InputMethodSubtype> are returned over IPC. Subtype string attributes had no length limit in the old code.
How the fix works
- Commit 558ee85e1d4a (core/java/android/view/inputmethod/InputMethodInfo.java, constructor): all TypedArray reads for the <input-method> tag and for each <subtype> tag now go through a new nested class TypedArrayWrapper (createForMethod / createForSubtype). All of them share one MetadataReadBytesTracker for the whole IME. getString() charges ret.length() * Character.BYTES (0 for null). getInt()/getResourceId() charge Integer.BYTES and getBoolean() charges 1 byte, but only when hasValue(index) is true. MetadataReadBytesTracker.onReadBytes() throws XmlPullParserException once the cumulative total exceeds MAX_METADATA_SIZE_BYTES (200*1024 bytes per the test comment). The wrapper is AutoCloseable: close() calls TypedArray.recycle(), replacing the manual sa.recycle()/a.recycle().
- Same commit: TypedArrayWrapper.getString() also enforces a per-attribute length via getMaxLength(index). For the <input-method> tag, InputMethod_settingsActivity is capped at COMPONENT_NAME_MAX_LENGTH (on 15/16 also InputMethod_languageSettingsActivity). All other method attributes and all subtype strings use Integer.MAX_VALUE. The si.name > COMPONENT_NAME_MAX_LENGTH check is moved out of the TypedArray block to just before the 'Validate file size using InputStream.skip()' loop. The subtype loop is restructured (continue on non-START_TAG, subtype built inside try-with-resources, then isAuxIme/subtypes.add after the block).
- Commit b9455ddd2a42: adds core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.{java,aidl}, a Parcelable that marshals the List<InputMethodInfo> into a byte[] and writes it with Parcel.writeBlob()/readBlob(). IInputMethodManager.aidl changes getInputMethodList() and getEnabledInputMethodList() to return InputMethodInfoSafeList. InputMethodManagerService wraps the results with InputMethodInfoSafeList.create()/empty(), and IInputMethodManagerGlobalInvoker unwraps them with InputMethodInfoSafeList.extractFrom(). The commit message states that the upstream flag guard was removed for this backport.
- Commit bc52aa800354: adds AbstractSafeList.java (shared marshall()/unmarshall()/extractFrom(), with a null-from check) and InputMethodSubtypeSafeList.{java,aidl}. InputMethodInfoSafeList is refactored to extend AbstractSafeList (empty() removed; create(null) yields an empty list). IInputMethodManager.aidl getEnabledInputMethodSubtypeList() now returns InputMethodSubtypeSafeList. InputMethodManagerService.getEnabledInputMethodSubtypeList() wraps the result with InputMethodSubtypeSafeList.create(), and IInputMethodManagerGlobalInvoker unwraps it with extractFrom(). In IMMS, the empty returns of getInputMethodList/getEnabledInputMethodList switch from empty() to create(null).
- Tests: InputMethodInfoTest gains TypedArrayWrapper unit tests (long settingsActivity rejected, 103 x 1000-char reads exceed the tracker, close() recycles). The new InputMethodInfoSafeListTest, AbstractSafeListTest and InputMethodSubtypeSafeListTest cover marshalling round trips.
Completeness
- Covered: every attribute read in the constructor, for both <input-method> and <subtype> tags, goes through a single per-IME MetadataReadBytesTracker. The sum of resolved string lengths (plus small fixed costs for ints, booleans and resource ids that are present) is therefore bounded at MAX_METADATA_SIZE_BYTES regardless of the number of subtypes. The raw XML file-size check is retained.
- Per-attribute string limits are narrow. In the Android 14 version, getMaxLength() applies COMPONENT_NAME_MAX_LENGTH only to InputMethod_settingsActivity. InputMethod_stylusHandwritingSettingsActivity and all subtype strings return Integer.MAX_VALUE (explicit TODO(b/456008595) and 'No limits for strings in subtype for now' comments). Those strings are bounded only by the cumulative tracker and by the resource limit DEFAULT_MAX_STRING_ATTR_LENGTH mentioned in the code comment.
- The class javadoc names STRING_ATTRIBUTES_MAX_CHAR_LENGTH as the limit for 'other string attributes', but the code does not use such a constant. Only the cumulative limit applies to them.
- getResourceId() charges Integer.BYTES only. The size of any resource referenced by id is not counted against this limit.
- Binder hardening covers the three list-returning IInputMethodManager methods (getInputMethodList, getEnabledInputMethodList, getEnabledInputMethodSubtypeList). getCurrentInputMethodInfoAsUser still returns a raw InputMethodInfo.
- In commit b9455ddd2a42, InputMethodInfoSafeList.extractFrom() dereferences from.mBuffer without a null check despite the @Nullable parameter. Commit bc52aa800354 adds the null check in AbstractSafeList.extractFrom(). All three commits should be applied together.
Behavior changes
- An IME whose read metadata attributes cumulatively exceed MAX_METADATA_SIZE_BYTES (200 KB per the test comment) now fails InputMethodInfo construction with XmlPullParserException ('The input method service has metadata exceeds the ... byte limit').
- The error message for an oversized settingsActivity changes from 'Activity name exceeds maximum of 1000 characters' to 'String resources in input method exceed the length limit of 1000 characters'. An oversized si.name is now rejected before the file-size validation with 'Input method name exceeds 1000 characters'.
- Absent int/boolean/resource-id attributes (hasValue false) are not charged. Null strings charge 0 bytes.
- IInputMethodManager.getInputMethodList / getEnabledInputMethodList / getEnabledInputMethodSubtypeList now return InputMethodInfoSafeList / InputMethodSubtypeSafeList (blob-backed) instead of List<...>. This is an AIDL signature change to the internal interface. Client-side extractFrom() returns a list of copies and clears the container, so a second extractFrom() on the same object returns an empty list.
- The upstream flag guard for InputMethodInfoSafeList was removed in the backport, so the new transport is unconditional on this branch.
Per major
- Android 14: Fixed in android-security-14.0.0_r25 by three cherry-picks: 558ee85e1d4a (parse hardening), b9455ddd2a42 (InputMethodInfoSafeList, upstream flag guard removed) and bc52aa800354 (InputMethodSubtypeSafeList/AbstractSafeList). Adapted: no languageSettingsActivity, isVirtualDeviceOnly or supportsConnectionlessStylusHandwriting attributes; getMaxLength() caps only InputMethod_settingsActivity; the test lives in core/tests/coretests. At android-security-14.0.0_r29, 7/8 lines of the patched region are present, and the SafeList classes and imports are visible in the code context.
- Android 15: Adapted fix in android-security-15.0.0_r13 (903125b03826): same TypedArrayWrapper/MetadataReadBytesTracker, plus languageSettingsActivity under Flags.imeSwitcherRevamp() and isVirtualDeviceOnly / supportsConnectionlessStylusHandwriting reads inside the wrapper. getMaxLength() caps settingsActivity and languageSettingsActivity. The test is in core/tests/InputMethodCoreTests. 7/8 lines of the patched region are present at android-security-15.0.0_r17.
- Android 16: Adapted fix in android-security-16.0.0_r4 (2bca2265ff3e): identical to 15 except the flag is Flags.imeSwitcherRevampApi(). 7/8 lines of the patched region are present at android-security-16.0.0_r8. SafeList commits for 15/16 are not shown in the material.
- Android 17: Not affected: not listed by the bulletin. 7/8 lines of the patched region are present at android-security-17.0.0_r1.
Unknowns
- The exact value and definition site of MAX_METADATA_SIZE_BYTES are not in the diff (the test comment states 200 * 1024 bytes).
- Which process parses IME metadata into InputMethodInfo, and from which call paths.
- Whether the two SafeList commits were also applied on Android 15 and 16 (only the parse-hardening commit is shown for those branches).
- Whether other IInputMethodManager implementations (e.g. ZeroJankProxy) exist on the security-14 branch and were adjusted; the shown diffs do not include them.
- Which of the four linked bugs corresponds to which symptom (OOM vs TransactionTooLargeException) is not stated.