CVE-2023-40089 AI-generated analysis
platform/frameworks/base, DevicePolicyManager / DevicePolicyManagerService (credential manager policy)
Makes DevicePolicyManager.getCredentialManagerPolicy() user-handle aware. The IDevicePolicyManager call now carries an explicit userId, the service looks up the profile/device owner for that user instead of the Binder caller's user, and cross-user queries require INTERACT_ACROSS_USERS.
Root cause
In DevicePolicyManagerService.java, getCredentialManagerPolicy() took no user argument and resolved the admin with getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), so it always used the user derived from the Binder calling identity. The client DevicePolicyManager.getCredentialManagerPolicy() did not pass the user of its Context (myUserId()). The policy returned therefore came from the calling user's profile/device owner, not from the user the DevicePolicyManager instance was bound to.
How the fix works
- core/java/android/app/admin/IDevicePolicyManager.aidl: signature changed from `PackagePolicy getCredentialManagerPolicy()` to `PackagePolicy getCredentialManagerPolicy(int userId)`.
- core/java/android/app/admin/DevicePolicyManager.java:getCredentialManagerPolicy(): now calls mService.getCredentialManagerPolicy(myUserId()). It is annotated @UserHandleAware(enabledSinceTargetSdkVersion = UPSIDE_DOWN_CAKE, requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS). throwIfParentInstance() is unchanged.
- services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java:getCredentialManagerPolicy(int userId): keeps the mHasFeature early return and the existing Preconditions.checkCallAuthorization(canWriteCredentialManagerPolicy(caller) || canQueryAdminPolicy(caller)). It adds `if (userId != caller.getUserId()) Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS))` and resolves the admin with getProfileOwnerOrDeviceOwnerLocked(userId) instead of caller.getUserId().
Completeness
- Covers the single getter getCredentialManagerPolicy end to end (AIDL, client, service).
- setCredentialManagerPolicy(in PackagePolicy policy) is untouched and still has no userId parameter.
- The diff adds no check that userId refers to an existing user. getProfileOwnerOrDeviceOwnerLocked(userId) is consulted, and null is returned when no admin is found.
- The client code shown passes myUserId() with no target-SDK branch. How the @UserHandleAware enabledSinceTargetSdkVersion attribute is enforced is not shown.
Behavior changes
- The IDevicePolicyManager.getCredentialManagerPolicy binder signature changed (it now takes int userId). Direct callers of the old transaction must be updated.
- When the requested userId differs from the Binder caller's user, the call now fails the authorization check unless the caller holds INTERACT_ACROSS_USERS.
- The returned PackagePolicy is now the one set by the profile/device owner of the Context's user rather than the Binder caller's user.
Per major
- Android 14: Same fix: commit e2e05f488da6 in android-security-14.0.0_r3 (cherry-pick of 0951b28bd94a). At android-security-14.0.0_r29, 7/8 lines of the patched region are present, and the code context shows the userId-aware client, the @UserHandleAware annotation and the AIDL signature getCredentialManagerPolicy(int userId).
- Android 15: Not affected per the bulletin. 7/8 lines of the patched region are present at android-security-15.0.0_r17.
- Android 16: Not affected per the bulletin. 7/8 lines of the patched region are present at android-security-16.0.0_r8.
- Android 17: Not affected per the bulletin. 7/8 lines of the patched region are present at android-security-17.0.0_r1.
Unknowns
- Which caller invoked getCredentialManagerPolicy on behalf of another user, and how the pre-fix behavior led to the EoP classification, is not shown in the material.
- Why the 8th line of the patched region is reported as not present at the latest tags is not shown.
- How the @UserHandleAware annotation attributes are enforced is not shown.