CVE-2025-0087 AI-generated analysis
platform/frameworks/base, packages/PackageInstaller (UninstallerActivity)
UninstallerActivity now only accepts a cross-user uninstall request when the requesting user is the profile parent of the target user, replacing a check that accepted any user returned by userManager.getUserProfiles().
Root cause
In packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java, when mDialogInfo.user was non-null the code accepted the request if userManager.getUserProfiles() contained mDialogInfo.user. It did not check whether the caller was the parent of the target profile. The commit message states the intended policy: only the parent profile can uninstall an app that is in a child profile.
How the fix works
- UninstallerActivity.java (the mDialogInfo.user check, hunk at about line 160): the getUserProfiles().contains(...) membership test is removed. If mDialogInfo.user equals Process.myUserHandle(), the request proceeds. Otherwise the code computes isCurrentUserProfileOwner = Process.myUserHandle().equals(userManager.getProfileParent(mDialogInfo.user)); if that is false it logs the same error, calls showUserIsNotAllowed() and returns, as the old rejection path did.
- The unused java.util.List import is dropped. The Android 15 commit (4c269d7b0ec7) contains the same logic change plus unrelated import reordering.
Completeness
- The fix covers the single user check in UninstallerActivity.java: self-user requests are allowed, requests from the profile parent of the target are allowed, and all other targets are rejected via showUserIsNotAllowed().
- Only this check site is changed. The material shows no other cross-user checks in PackageInstaller (for example in the v2 UninstallLaunch path imported on Android 15) and does not show how mDialogInfo.user is populated, so whether equivalent validation exists elsewhere cannot be judged from the material.
- If userManager.getProfileParent(mDialogInfo.user) returns null, the equals comparison fails and the request is rejected, which is the restrictive outcome.
Behavior changes
- Uninstall requests targeting a user other than the caller's are now rejected (showUserIsNotAllowed) unless the caller's user is the profile parent of the target. Previously, any target in the caller's getUserProfiles() result was accepted.
- Requests where the target user equals the caller's user no longer go through the getUserProfiles() lookup.
- The error log text is unchanged; no new return codes are introduced.
Per major
- Android 14: same fix: 61762eea6f1e in android-security-14.0.0_r18 (RESTRICT AUTOMERGE cherry-pick); 8/8 patched lines present at android-security-14.0.0_r29.
- Android 15: adapted fix: 4c269d7b0ec7 in android-security-15.0.0_r6, with identical logic plus import reordering in a file that already imports the v2 UninstallLaunch and common.* classes; 8/8 lines present at android-security-15.0.0_r17.
- Android 16: not affected per the bulletin (not listed); the patched region is present (8/8 lines) at android-security-16.0.0_r8.
- Android 17: not affected per the bulletin (not listed); the patched region is present (8/8 lines) at android-security-17.0.0_r1.
Unknowns
- How mDialogInfo.user is populated (the code that parses the launching intent is not in the material).
- Exactly which caller/target user relationships the old getUserProfiles() check accepted.
- Whether the v2 PackageInstaller UI path (UninstallLaunch, present on Android 15) performs its own user check; not shown.
- Why Android 16 and 17 are not listed by the bulletin although the patched region is present there.