CVE-2024-31319 AI-generated analysis
platform/frameworks/base, services/core notification (NotificationManagerService, privileged listener channel update)
Adds a URI read-permission check in NotificationManagerService.updateNotificationChannelFromPrivilegedListener so a privileged (CDM) NotificationListenerService can only set a new channel sound URI that its own UID is allowed to read.
Root cause
updateNotificationChannelFromPrivilegedListener only called verifyPrivilegedListener(token, user, false) and then passed the caller-supplied NotificationChannel straight to updateNotificationChannelInt. The channel's sound URI (channel.getSound()) was accepted without checking that the calling UID has read access to that URI, so a privileged listener could store a content URI as a channel sound in another package's channel without holding permission for it.
How the fix works
- services/core/java/com/android/server/notification/NotificationManagerService.java:updateNotificationChannelFromPrivilegedListener: after verifyPrivilegedListener, looks up the existing channel via mPreferencesHelper.getNotificationChannel(pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true) and calls the new verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel) before updateNotificationChannelInt.
- services/core/java/com/android/server/notification/NotificationManagerService.java:verifyPrivilegedListenerUriPermission (new): if updateChannel.getSound() is non-null and differs (Objects.equals) from the original channel's sound, it calls mUgmInternal.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(soundUri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(soundUri, UserHandle.getUserId(sourceUid))) inside Binder.withCleanCallingIdentity. The check is made against the caller's UID (sourceUid), so a SecurityException aborts the update before updateNotificationChannelInt runs.
- services/tests/uiservicestests/.../NotificationManagerServiceTest.java: adds testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission (expects SecurityException, no updateNotificationChannel, no listener notification) and ..._sameSound (unchanged sound URI is not re-checked and the update proceeds).
Completeness
- Covers only the sound URI of the channel, and only when it is non-null and different from the currently stored channel's sound; an unchanged sound URI is deliberately not re-checked (verified by the _sameSound test).
- Only the privileged-listener entry point updateNotificationChannelFromPrivilegedListener is changed. Other channel update entry points in the same service (e.g. updateNotificationChannelForPackage, seen in the test context) are not touched by this commit; the material does not show whether they already perform an equivalent check.
- If no original channel exists (originalChannel == null), the check still runs against any non-null new sound URI.
Behavior changes
- updateNotificationChannelFromPrivilegedListener now throws SecurityException (propagated from mUgmInternal.checkGrantUriPermission) when the caller lacks read permission for a newly supplied sound URI; in that case no channel update and no notifyNotificationChannelChanged occur.
- One additional mPreferencesHelper.getNotificationChannel lookup and a second getUidForPackageAndUser call per update; the permission check itself runs with cleared calling identity.
Per major
- Android 14: same fix: commit f428043dbaaf in android-security-14.0.0_r9 (cherry-pick of 9b7bbbf5ad54); at android-security-14.0.0_r29 all 8/8 lines of the patched region are present.
- Android 15: not affected (not listed by the bulletin); 8/8 lines of the patched region present at android-security-15.0.0_r17.
- Android 16: not affected (not listed by the bulletin); 7/8 lines of the patched region present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin); 7/8 lines of the patched region present at android-security-17.0.0_r1.
Unknowns
- The material does not show how the stored sound URI is later consumed, only that the URI was accepted without a permission check.
- Whether sibling channel update/create paths (e.g. updateNotificationChannelForPackage) already validate sound URI access is not visible in the material.
- The exact code applied to Android 12/12L/13 is not shown; only the Android 14 commit is provided.
- Which line of the patched region differs on Android 16/17 (7/8 match) is not shown.
- Whether updateNotificationChannelInt creates a channel when none exists is not shown.