CVE-2025-48652 AI-generated analysis
platform/frameworks/base, packages/PackageInstaller (InstallStart activity, and the PIA v2 InstallRepository on 16/17)
PackageInstaller's InstallStart no longer lets a caller that holds INSTALL_PACKAGES skip the unknown-sources user-restriction checks when it starts the installer with an ACTION_VIEW or ACTION_INSTALL_PACKAGE intent. The bypass now applies only to non-intent installs by INSTALL_PACKAGES holders and to privileged callers that set EXTRA_NOT_UNKNOWN_SOURCE.
Root cause
In InstallStart.onCreate, checkDevicePolicyRestrictions(isTrustedSource) decided which user restrictions to enforce. When isTrustedSource was true, only DISALLOW_INSTALL_APPS was checked. Otherwise the unknown-sources restrictions were checked as well. Judging from the removed Kotlin helper isInstallRequestFromTrustedSource on 16/17 and from the commit message, isTrustedSource was true when the caller was a privileged app that set EXTRA_NOT_UNKNOWN_SOURCE OR when the caller held INSTALL_PACKAGES. The INSTALL_PACKAGES condition did not look at how the installer was launched. As a result, an intent-driven install (ACTION_VIEW / ACTION_INSTALL_PACKAGE) from an INSTALL_PACKAGES holder skipped the unknown-sources user restrictions.
How the fix works
- packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java:onCreate: stores intentAction = intent.getAction() and computes isIntentInstall = ACTION_VIEW or ACTION_INSTALL_PACKAGE.
- InstallStart.java:onCreate: computes bypassUnknownSourceRestrictions = (!isIntentInstall && isInstallPkgPermissionGranted) || isPrivilegedAndKnown from the existing locals isInstallPkgPermissionGranted and isPrivilegedAndKnown, and passes it to checkDevicePolicyRestrictions in place of isTrustedSource.
- InstallStart.java:checkDevicePolicyRestrictions: the parameter is renamed to bypassUnknownSourceRestrictions. When it is true, only DISALLOW_INSTALL_APPS is checked; when false, the unknown-sources restrictions are checked too.
- On Android 16 and 17 the commit also patches packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt. The isInstallRequestFromTrustedSource helper is inlined as isPrivilegedAndKnown and isInstallPkgPermissionGranted, with an INVALID_UID guard: new on 16 using callingUid, already present on 17 using originatingUid. isTrustedSource becomes their OR, and getDevicePolicyRestrictions receives the same bypassUnknownSourceRestrictions expression. The Android 15 commit does not touch this file.
- The commit is titled 'Reapply' and reverts the revert 29962260bd04. Its Cherrypick-From lines list 81f83fdb0944, 6e0b7c02e54a and 9d20d0ae8fef.
Completeness
- Covers the legacy InstallStart.java path. Intent installs (ACTION_VIEW, ACTION_INSTALL_PACKAGE) now bypass the unknown-sources restrictions only for privileged callers that set EXTRA_NOT_UNKNOWN_SOURCE.
- Non-intent installs by INSTALL_PACKAGES holders keep the bypass. The commit message says this is intended.
- On Android 15 only InstallStart.java is patched. The code at android-security-15.0.0_r17 shows a usePiaV2() branch that forwards to InstallLaunch before the patched logic runs. The Android 15 commit does not modify v2/model/InstallRepository.kt, while the 16 and 17 commits do. The material does not show whether PIA v2 is enabled on Android 15, or what that path does there.
- The restriction lists themselves are not changed. The fix only changes which callers get the reduced list.
Behavior changes
- Apps holding INSTALL_PACKAGES that launch PackageInstaller with ACTION_VIEW or ACTION_INSTALL_PACKAGE are now subject to the unknown-sources user restrictions. When such a restriction is set they are blocked (admin support flow).
- No change for non-intent installs by INSTALL_PACKAGES holders, or for privileged apps that set EXTRA_NOT_UNKNOWN_SOURCE on an intent install.
- Android 16 Kotlin path only: when callingUid is INVALID_UID, isPermissionGranted is no longer called and the isInstallPermissionGrantedOrRequested abort is skipped. On both 16 and 17, isInstallRequestFromTrustedSource is removed.
Per major
- Android 14: Not affected: the bulletin does not list Android 14. 6/8 lines of the patched region are present at android-security-14.0.0_r29. The material identifies no fix commit for 14.
- Android 15: Fixed by 0985478406c2 in android-security-15.0.0_r13 (Change-Id Ib917acb2c4738f6a4758b8ca149b80943f00acca). Only InstallStart.java is patched. 8/8 lines present at android-security-15.0.0_r17.
- Android 16: Same change (4dc009cd724c, android-security-16.0.0_r4), plus a hunk that patches v2/model/InstallRepository.kt in the same way: the trust computation is inlined with a callingUid INVALID_UID guard, and bypassUnknownSourceRestrictions is passed to getDevicePolicyRestrictions. 8/8 lines present at android-security-16.0.0_r8.
- Android 17: Commit 81f83fdb0944 in android-17.0.0_r1 (matched by related_bug), which is listed as a Cherrypick-From source of the 15 commit. It patches InstallStart.java, where no new intentAction local is added, and InstallRepository.kt, using originatingUid. 7/8 lines present at android-security-17.0.0_r1.
Unknowns
- Whether PIA v2 (usePiaV2()) is enabled on Android 15 builds, and whether the Android 15 InstallRepository.kt has the same unpatched logic.
- Why the original landing was reverted (29962260bd04) and which issues the reland fixed.
- The exact definitions of isTrustedSource, isInstallPkgPermissionGranted and isPrivilegedAndKnown in the Android 15 InstallStart.java, and any other uses of isTrustedSource there.
- The exact list of unknown-sources restriction constants in checkDevicePolicyRestrictions (the diff cuts it off).