CVE-2025-48635 AI-generated analysis
platform/frameworks/base, WindowManager / TaskFragmentOrganizerController (activity embedding)
TaskFragmentOrganizerController now refuses to register a TaskFragment organizer from a non-positive pid and only hands the real activity token to an organizer when both the activity's pid and uid match the organizer's, preventing an activity token from being leaked to another process.
Root cause
The organizer registration path in TaskFragmentOrganizerController.java (hunk near line 430) stored new TaskFragmentOrganizerState(organizer, pid, uid) without validating the pid. Per the commit message, a malicious app could register the organizer via a one-way binder call to disguise itself as running on pid 0. prepareActivityReparentedToTask decided whether to pass the real activity.token or a temporary "TemporaryActivityToken" Binder by comparing only activity.getPid() with mOrganizerPid. As a result, the real token of an activity not belonging to the organizer process could be sent in the TYPE_ACTIVITY_REPARENTED_TO_TASK change.
How the fix works
- services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java, organizer registration path (before mTaskFragmentOrganizerState.put): adds `if (pid <= 0) throw new IllegalStateException("Cannot register from invalid pid: " + pid)`.
- services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java : TaskFragmentOrganizerState.prepareActivityReparentedToTask: the condition for passing the real token changes from `activity.getPid() == mOrganizerPid` to `activity.getPid() == mOrganizerPid && activity.getUid() == mOrganizerUid`. Otherwise the existing fallback creates a temporary Binder token stored in mTemporaryActivityTokens and removed after TEMPORARY_ACTIVITY_TOKEN_TIMEOUT_MS.
- Single commit 36e65fce2d51 in android-security-14.0.0_r25 (lists three Cherrypick-From changes), 6 insertions and 1 deletion in one file.
Completeness
- The fix changes both the registration path (rejects pid <= 0) and the real-token decision in prepareActivityReparentedToTask (adds a uid match).
- The material does not show whether mOrganizerPid is used elsewhere as an ownership test, or whether other organizer controllers record pids the same way.
- The earlier task-level checks (task.effectiveUid != mOrganizerUid, isAllowedToEmbedActivity, isAllowedToEmbedActivityInTrustedMode) are unchanged.
Behavior changes
- Organizer registration now throws IllegalStateException("Cannot register from invalid pid: <pid>") when pid <= 0; previously such registrations succeeded.
- An activity whose pid matches the organizer pid but whose uid differs now gets a temporary token (with the existing timeout cleanup) instead of the real activity.token.
Per major
- Android 14: same fix: commit 36e65fce2d51 in android-security-14.0.0_r25; at android-security-14.0.0_r29 7/8 lines of the patched region are present.
- Android 15: announced-not-published: bulletin lists 15 as affected but no public commit resolved; at android-security-15.0.0_r17 6/8 lines of the patched region are present, fix state not confirmable from the material.
- Android 16: not affected per the bulletin (not listed); at android-security-16.0.0_r8 6/8 lines of the patched region are present.
- Android 17: not affected per the bulletin (not listed); at android-security-17.0.0_r1 6/8 lines of the patched region are present.
Unknowns
- How the pid passed to the registration path is obtained is not shown in the diff context.
- Which activities match the organizer pid 0 in practice is not shown.
- Which of the three Cherrypick-From changes correspond to which hunk.
- Whether the 6/8 lines present on the Android 15/16/17 branches indicate a partial fix, a differently worded fix, or context drift.
- Why the bulletin affected-versions list includes 16-qpr2-next while Android 16 is not listed per the per-major facts.