CVE-2023-40081 AI-generated analysis
platform/frameworks/base, SystemUI media controls (MediaDataManager) plus UriGrantsManagerService / IUriGrantsManager
SystemUI's MediaDataManager now asks UriGrantsManagerService, through a new hidden binder method checkGrantUriPermission_ignoreNonSystem, whether the media app's uid may read a resumable media artwork URI before SystemUI loads that bitmap.
Root cause
In packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt, the resumption path (the "adding track for $userId from browser" code that builds MediaData from a MediaDescription) called loadBitmapFromUri(desc.iconUri!!) directly when desc.iconBitmap was null. It never checked whether the originating app (appUid/packageName) had read access to that URI.
How the fix works
- core/java/android/app/IUriGrantsManager.aidl: adds a new hidden binder method, int checkGrantUriPermission_ignoreNonSystem(int sourceUid, String targetPkg, in Uri uri, int modeFlags, int userId).
- services/core/java/com/android/server/uri/UriGrantsManagerService.java:checkGrantUriPermission_ignoreNonSystem: new implementation. It first calls the new private helper isCallerIsSystemOrPrivileged(), which accepts SYSTEM_UID, ROOT_UID, or a caller holding INTERACT_ACROSS_USERS_FULL (checked via ActivityManager.checkComponentPermission). For a non-privileged caller it returns Process.INVALID_UID without throwing. Otherwise it clears the calling identity, delegates to the existing checkGrantUriPermissionUnlocked(callingUid, targetPkg, uri, modeFlags, userId) and restores the identity in finally. Per its javadoc, that method throws SecurityException if the grant is not allowed.
- packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt: in the resumption path, the lookups currentEntry = mediaEntries.get(packageName) and appUid = currentEntry?.appUid ?: Process.INVALID_UID now happen before the artwork load. loadBitmapFromUri(desc.iconUri!!) is replaced by loadBitmapFromUriForUser(desc.iconUri!!, userId, appUid, packageName).
- MediaDataManager.kt:loadBitmapFromUriForUser (new): calls UriGrantsManager.getService().checkGrantUriPermission_ignoreNonSystem(appUid, packageName, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, userId)). It calls loadBitmapFromUri(uri) only if that call does not throw. On SecurityException it logs "Failed to get URI permission" and returns null.
- packages/SystemUI/tests/.../MediaDataManagerTest.kt: adds static mocks for UriGrantsManager and ImageDecoder. It also adds two tests, testResumeMediaLoaded_hasArtPermission_artLoaded and testResumeMediaLoaded_noArtPermission_noArtLoaded, which check that artwork is loaded only when the check does not throw.
Completeness
- The fix covers only the resumable media path in MediaDataManager.kt. The generic loadBitmapFromUri helper is kept, and the diff does not show its other call sites, so the material does not show whether those sites have a separate check.
- The grant check uses appUid = currentEntry?.appUid ?: Process.INVALID_UID. If mediaEntries has no entry for packageName, the check runs with callingUid = -1. The material does not show how checkGrantUriPermissionUnlocked handles that value.
- checkGrantUriPermission_ignoreNonSystem fails open for non-privileged callers: it returns INVALID_UID instead of throwing. The SystemUI caller ignores the return value and stops only on SecurityException, so the check is effective only if SystemUI passes isCallerIsSystemOrPrivileged(). The material does not show SystemUI's permissions.
- The check uses only FLAG_GRANT_READ_URI_PERMISSION, which matches the read-only use (bitmap decode).
Behavior changes
- Resumable media artwork given by URI is now dropped (artwork is null and Log.e reports "Failed to get URI permission") when the check throws SecurityException for the media app's uid.
- system_server gains the new hidden binder method IUriGrantsManager.checkGrantUriPermission_ignoreNonSystem. It returns -1 for callers that are not system or root and lack INTERACT_ACROSS_USERS_FULL. For other callers it delegates to checkGrantUriPermissionUnlocked.
- One extra binder call to system_server happens for each resumable-media artwork load that uses iconUri.
Per major
- Android 14: same fix: commit 162be1ccbbb0 in android-security-14.0.0_r3 (cherry-pick of 470f62bc8954, Change-Id Ie79915d3d1712f08dc2e8dfbd5bc7fd32bb308a3). At android-security-14.0.0_r29, 8/8 lines of the patched region are present.
- Android 15: not affected (not listed by the bulletin). The patched region (8/8 lines) is present at android-security-15.0.0_r17.
- Android 16: not affected (not listed by the bulletin). The patched region (8/8 lines) is present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin). The patched region (8/8 lines) is present at android-security-17.0.0_r1.
Unknowns
- How checkGrantUriPermissionUnlocked behaves when callingUid is Process.INVALID_UID (no existing media entry for the package).
- Whether other callers of loadBitmapFromUri in MediaDataManager.kt have an equivalent URI permission check.
- Whether SystemUI passes isCallerIsSystemOrPrivileged(), i.e. holds INTERACT_ACROSS_USERS_FULL; otherwise the check returns -1 and never throws.
- The exact fix commits and file paths on the Android 12, 12L and 13 branches; the material contains only the Android 14 commit.