CVE-2026-0011 AI-generated analysis
platform/frameworks/base, PackageManagerService / Settings (system app enable/disable, UID migration)
Makes Settings.enableSystemPackageLPw able to reuse the disabled PackageSetting of a shared-UID system app when its update is uninstalled. addPackageLPw now accepts the package even when registerExistingAppId fails for a shared-UID package, and the shared user app ID is restored on the reused setting, so the preloaded app is no longer re-scanned and installed as a new app with a possibly different UID.
Root cause
In services/core/java/com/android/server/pm/Settings.java, enableSystemPackageLPw rebuilds a disabled system package's setting through addPackageLPw. This happens when the system app's update is uninstalled. addPackageLPw creates a new PackageSetting and only puts it into mPackages if mAppIds.registerExistingAppId(uid, p, name) succeeds. Per the commit message, registerExistingAppId fails for shared-uid packages, so the disabled setting is not reused. Instead, the preloaded version is re-scanned and installed as a new app. When the manifest has sharedUserMaxSdkVersion, this changes the app's UID. Also, the rebuilt setting did not have its shared user app ID copied from the disabled setting.
How the fix works
- Settings.java:addPackageLPw: adds a new boolean parameter, hasSharedUser. The condition that admits the new PackageSetting into mPackages becomes 'mAppIds.registerExistingAppId(uid, p, name) || hasSharedUser', so a shared-UID package is accepted even when registerExistingAppId fails.
- Settings.java:enableSystemPackageLPw: passes p.hasSharedUser() from the disabled setting to addPackageLPw. After a non-null return it calls ret.setSharedUserAppId(p.getSharedUserAppId()), alongside the existing setAppMetadataFilePath and setUpdatedSystemApp(false).
- Settings.java, settings-reading path (the addPackageLPw call that logs "Reading package"): passes hasSharedUser=false, which keeps the prior behavior for settings read from disk.
- services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt: the addPackageLPw mock gains one more nullable() argument to match the new signature.
Completeness
- Only the enableSystemPackageLPw path passes the real hasSharedUser value. The settings-reading caller explicitly passes false, so the relaxed condition only affects re-enabling a disabled system package.
- The new hasSharedUser bypass does not check that uid is consistent with the shared user's app ID. It relies on the disabled setting's state. Whether the setting is re-linked to the SharedUserSetting package list is not shown in this diff.
- The fallback path (re-scanning the preloaded version as a new app) is not changed. For shared-UID system apps, the fix avoids reaching it.
Behavior changes
- For shared-UID system apps, enableSystemPackageLPw can now return a reused PackageSetting where it previously failed. The update-uninstall path then reuses the disabled setting, as it already does for non-shared-UID system apps, instead of re-scanning and installing the preloaded version as a new package.
- The restored setting carries the original sharedUserAppId from the disabled setting.
- addPackageLPw has a new signature (an extra boolean), which affects all callers and test mocks.
Per major
- Android 14: Same fix (77d8e59a1af6 in android-security-14.0.0_r25). The 17-argument addPackageLPw is extended with hasSharedUser, the settings-reading caller passes false, enableSystemPackageLPw sets sharedUserAppId, and MockSystem.kt is updated. At android-security-14.0.0_r29, 7/8 lines of the patched region are present.
- Android 15: Adapted fix (65e7256522b4 in android-security-15.0.0_r13). Same logic on the shorter addPackageLPw(name, realName, codePath, uid, pkgFlags, pkgPrivateFlags, domainSetId, isSdkLibrary) signature. The condition becomes '(uid == INVALID_UID && isSdkLibrary && Flags.disallowSdkLibsToBeApps()) || registerExistingAppId(...) || hasSharedUser'. The reading caller passes false, and setSharedUserAppId is added after setInstallSource. At android-security-15.0.0_r17, 7/8 lines of the patched region are present.
- Android 16: Adapted fix (51368785bd09 in android-security-16.0.0_r4), identical in content to the Android 15 variant at shifted line numbers. At android-security-16.0.0_r8, 7/8 lines of the patched region are present.
- Android 17: Not affected per the bulletin (not listed). At android-security-17.0.0_r1, 4/8 lines of the patched region are present.
Unknowns
- Why registerExistingAppId fails for shared-uid packages (AppIds internals) is not shown.
- The caller of enableSystemPackageLPw and the fallback re-scan path where the UID changes are not in the material.
- Why the bulletin rates this as EoP is not stated in the material.
- Which line of the patched region is missing at the latest 14/15/16 tags, and how the Android 17 code differs, is not shown.