CVE-2025-32313 AI-generated analysis
platform/frameworks/native libbinder Parcel; platform/frameworks/base core (android.app.usage.UsageEvents, android.app.NotificationHistory)
Fixes Parcel::appendFrom to decide whether to grow the buffer based on the current write position (mDataPos) instead of mDataSize, and adds validation in UsageEvents(Parcel) and NotificationHistory(Parcel) that a parcel-supplied position value does not exceed the rebuilt parcel's data size before it is applied with setDataPosition.
Root cause
In libs/binder/Parcel.cpp, Parcel::appendFrom checked `(mDataSize+len) > mDataCapacity` to decide whether to call growData(len). The fix makes the check depend on mDataPos, which implies the appended bytes go at the current data position. If mDataPos had been moved beyond mDataSize (for example by setDataPosition with an unchecked value), the old capacity test could pass even though the range at mDataPos + len went beyond mDataCapacity. On the Java side, UsageEvents(Parcel) and NotificationHistory(Parcel) read `positionInParcel` directly from the incoming blob. They passed it to mParcel.setDataPosition() without comparing it to mParcel.dataSize(), so a crafted parcel could leave the internal Parcel at an arbitrary data position.
How the fix works
- libs/binder/Parcel.cpp:Parcel::appendFrom (frameworks/native 4e28321ba198): the grow condition changes from `(mDataSize+len) > mDataCapacity` to `(mDataPos + len) > mDataCapacity`. A new test, binderParcelUnitTest.cpp TEST(Parcel, AppendWithBadDataPos), sets dataCapacity 8 and dataPosition 10000 and expects appendFrom(&p1, 0, 8) to return BAD_VALUE.
- core/java/android/app/usage/UsageEvents.java:UsageEvents(Parcel in) (frameworks/base d02a81da9715): after appendFrom and setDataSize(mParcel.dataPosition()), adds `if (positionInParcel > mParcel.dataSize()) throw new IllegalArgumentException(...)` before mParcel.setDataPosition(positionInParcel).
- core/java/android/app/NotificationHistory.java:NotificationHistory(Parcel in) (frameworks/base daa876427451): the same check, throwing IllegalStateException when positionInParcel > mParcel.dataSize(), before mParcel.setDataPosition(positionInParcel).
Completeness
- The native change covers only Parcel::appendFrom. The diff touches no other Parcel write path, and the material does not show whether other writers compute growth from mDataSize.
- The Java checks guard only the upper bound (positionInParcel > dataSize), so positionInParcel == dataSize is accepted. The new condition does not reject negative values; the material does not show how setDataPosition handles them.
- Only UsageEvents and NotificationHistory, the two parcelables changed by the frameworks/base commits for this bug, get the position validation. Both use the same blob + listByteLength + positionInParcel layout. The material does not show whether other Parcelables use the same pattern.
- Per-major facts report the native patched region as 5/6 lines present at android-security-14.0.0_r29 and 15.0.0_r17. The Parcel.cpp code context supplied for r29 does not cover the appendFrom region, so the material cannot confirm the exact state of that line.
Behavior changes
- UsageEvents(Parcel) now throws IllegalArgumentException("Obtained an invalid position value(...) from Parcel.") when the embedded position exceeds the reconstructed parcel's data size.
- NotificationHistory(Parcel) now throws IllegalStateException with a similar message under the same condition.
- Parcel::appendFrom now decides growth from mDataPos + len instead of mDataSize + len; per the new unit test, an append at a position far beyond capacity returns BAD_VALUE. Per index search, errors reach callers such as android_os_Parcel_appendFrom (signalExceptionForError) and AParcel_appendFrom (PruneStatusT).
Per major
- Android 14: Same fix. Three commits in android-security-14.0.0_r25: frameworks/native 4e28321ba198 (appendFrom), and frameworks/base d02a81da9715 (UsageEvents, RESTRICT AUTOMERGE) and daa876427451 (NotificationHistory). At r29 the native patched region is reported as 5/6 lines present, and both Java checks appear in the r29 context.
- Android 15: Same native fix: frameworks/native dc54178de228 in android-security-15.0.0_r13. It is the same one-line change at a different offset (hunk at line 542), with the test inserted after AppendPlainDataPartial. The material does not show Java-side commits for 15. At r17 the native patched region is 5/6 lines present.
- Android 16: The material shows frameworks/base 283bef4b2546 (NotificationHistory check, same diff as on 14) in android-security-16.0.0_r4. The native and UsageEvents commits for 16 are not shown. At r8 the patched region is 4/4 lines present.
- Android 17: Not affected per the bulletin. At android-security-17.0.0_r1 the patched region is 5/5 lines present.
Unknowns
- Which privileged consumer of UsageEvents/NotificationHistory parcels is the EoP target.
- The code path inside growData/continueWrite that yields BAD_VALUE in the new test; growData is not shown.
- Whether 15 and 16 also received the UsageEvents change, whether 15 received the NotificationHistory change, and whether 16 received the native change. Only the listed commits are shown.
- Why the native patched region is reported as 5/6 lines present on 14 r29 and 15 r17; the Parcel.cpp context supplied does not cover appendFrom.
- Whether the UsageEvents and NotificationHistory commits depend on the native change.