diff options
2 files changed, 85 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e01d6a7d9b36..cf67ef399092 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -5772,6 +5772,10 @@ public class NotificationManagerService extends SystemService {              Objects.requireNonNull(user);              verifyPrivilegedListener(token, user, false); + +            final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( +                    pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true); +            verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel);              updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);          } @@ -5863,6 +5867,24 @@ public class NotificationManagerService extends SystemService {              }          } +        private void verifyPrivilegedListenerUriPermission(int sourceUid, +                @NonNull NotificationChannel updateChannel, +                @Nullable NotificationChannel originalChannel) { +            // Check that the NLS has the required permissions to access the channel +            final Uri soundUri = updateChannel.getSound(); +            final Uri originalSoundUri = +                    (originalChannel != null) ? originalChannel.getSound() : null; +            if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) { +                Binder.withCleanCallingIdentity(() -> { +                    mUgmInternal.checkGrantUriPermission(sourceUid, null, +                            ContentProvider.getUriWithoutUserId(soundUri), +                            Intent.FLAG_GRANT_READ_URI_PERMISSION, +                            ContentProvider.getUserIdFromUri(soundUri, +                            UserHandle.getUserId(sourceUid))); +                }); +            } +        } +          private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {              int uid = INVALID_UID;              final long identity = Binder.clearCallingIdentity(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 8490a3a052f1..59b20bba7390 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3593,6 +3593,69 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {      }      @Test +    public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission() +            throws Exception { +        mService.setPreferencesHelper(mPreferencesHelper); +        when(mCompanionMgr.getAssociations(PKG, mUserId)) +                .thenReturn(singletonList(mock(AssociationInfo.class))); +        when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), +                eq(mTestNotificationChannel.getId()), anyBoolean())) +                .thenReturn(mTestNotificationChannel); + +        final Uri soundUri = Uri.parse("content://media/test/sound/uri"); +        final NotificationChannel updatedNotificationChannel = new NotificationChannel( +                TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); +        updatedNotificationChannel.setSound(soundUri, +                updatedNotificationChannel.getAudioAttributes()); + +        doThrow(new SecurityException("no access")).when(mUgmInternal) +                .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), +                anyInt(), eq(Process.myUserHandle().getIdentifier())); + +        assertThrows(SecurityException.class, +                () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, PKG, +                Process.myUserHandle(), updatedNotificationChannel)); + +        verify(mPreferencesHelper, never()).updateNotificationChannel( +                anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean()); + +        verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), +                eq(Process.myUserHandle()), eq(mTestNotificationChannel), +                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); +    } + +    @Test +    public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound() +            throws Exception { +        mService.setPreferencesHelper(mPreferencesHelper); +        when(mCompanionMgr.getAssociations(PKG, mUserId)) +                .thenReturn(singletonList(mock(AssociationInfo.class))); +        when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(), +                eq(mTestNotificationChannel.getId()), anyBoolean())) +                .thenReturn(mTestNotificationChannel); + +        final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; +        final NotificationChannel updatedNotificationChannel = new NotificationChannel( +                TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); +        updatedNotificationChannel.setSound(soundUri, +                updatedNotificationChannel.getAudioAttributes()); + +        doThrow(new SecurityException("no access")).when(mUgmInternal) +                .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), +                    anyInt(), eq(Process.myUserHandle().getIdentifier())); + +        mBinderService.updateNotificationChannelFromPrivilegedListener( +                null, PKG, Process.myUserHandle(), updatedNotificationChannel); + +        verify(mPreferencesHelper, times(1)).updateNotificationChannel( +                anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean()); + +        verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), +                eq(Process.myUserHandle()), eq(mTestNotificationChannel), +                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); +    } + +    @Test      public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {          mService.setPreferencesHelper(mPreferencesHelper);          when(mCompanionMgr.getAssociations(PKG, mUserId))  |