CVE-2025-32312 AI-generated analysis
platform/frameworks/base, core/java/android/content/pm/PackageParser.java (component parcel deserialization, createIntentsList)
Adds a type check in PackageParser's createIntentsList so that a class read by name from a Parcel is only constructed if it is a subclass of IntentInfo. Before, the code reflectively constructed any class named in the parcel.
Root cause
createIntentsList(Parcel in) reads a count N and then a String componentName from the Parcel. It calls Class.forName(componentName), looks up a constructor that takes a Parcel, and calls cons.newInstance(in) N times. Nothing checked that the named class was an IntentInfo subclass, so any class with a public (Parcel) constructor named in the parcel data would be loaded and constructed from the rest of the parcel. The writer side (writeIntentsList) only ever writes info.getClass().getName() of a real IntentInfo, but the reader trusted the string without checking it.
How the fix works
- core/java/android/content/pm/PackageParser.java : createIntentsList(Parcel): right after Class.forName(componentName), the fix adds `if (!IntentInfo.class.isAssignableFrom(cls)) throw new AssertionError("Intent list requires subclass of IntentInfo, not: " + componentName);`. As a result, getConstructor(Parcel.class) and newInstance(in) are only reached for IntentInfo subclasses.
- The new AssertionError is thrown inside the existing try block. It is not a ReflectiveOperationException, so it propagates out of createIntentsList instead of being caught and rewrapped by the existing catch.
- Single-file, four-line change. writeIntentsList and the IntentInfo subclasses are not changed.
Completeness
- Covers the only reflective construction site shown: createIntentsList now rejects any class that is not an IntentInfo subtype before it looks up or calls a constructor.
- Class.forName(componentName) still runs before the check, so the named class is still loaded and statically initialized. Only construction is prevented.
- Any IntentInfo subclass with a (Parcel) constructor is still accepted. The fix enforces the type bound only and does not restrict the class to specific known subclasses.
- A rejected class causes an AssertionError to propagate out of createIntentsList, the same way existing reflective failures are reported.
Behavior changes
- Unparceling an intents list that names a class which is not an IntentInfo subclass now throws AssertionError ("Intent list requires subclass of IntentInfo, not: <name>") instead of constructing that class.
- Well-formed parcels produced by writeIntentsList behave as before, because they always name an IntentInfo subclass.
Per major
- Android 14: same fix: platform/frameworks/base 577cdba1048c in android-security-14.0.0_r21 (cherry-pick of 65c1a90bf4af). All 4 patched lines are present at android-security-14.0.0_r29.
- Android 15: same fix: platform/frameworks/base 95eda53ff1d0 in android-security-15.0.0_r9, identical hunk (offset +1 line). All 4 lines are present at android-security-15.0.0_r17.
- Android 16: same fix: commit 65c1a90bf4af in android-16.0.0_r2, identical hunk. All 4 lines are present at android-security-16.0.0_r8.
- Android 17: not affected per the bulletin (Android 17 is not listed). The patched region (4/4 lines) is already present at android-security-17.0.0_r1.
Unknowns
- Which binder interfaces or callers pass untrusted Parcels into createIntentsList. The material shows no callers.
- Whether a fix landed on Android 13, which is listed as affected but has no commit in the material.
- Whether a test covers the rejection path. The commit only cites atest PackageParsingPerfTest.