Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba46960b authored by Valentin Iftime's avatar Valentin Iftime Committed by Android Build Coastguard Worker
Browse files

Verify URI permission for channel sound update from NotificationListenerService

 Check that a privileged NotificationListenerService (CDM) has the permission to access the sound URI
  when updating a notification channel.

Test: atest com.android.server.notification.NotificationManagerServiceTest#testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission
Bug: 317357401
(cherry picked from commit 9b7bbbf5)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f090c0538a27d8658d8a860046d5c5e931302341)
Merged-In: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
Change-Id: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
parent cea77d57
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -5434,6 +5434,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);
        }

@@ -5513,6 +5517,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();
+67 −0
Original line number Diff line number Diff line
@@ -2629,6 +2629,73 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
    }

    @Test
    public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
            throws Exception {
        mService.setPreferencesHelper(mPreferencesHelper);
        List<String> associations = new ArrayList<>();
        associations.add("a");
        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
                .thenReturn(associations);
        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());

        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);
        List<String> associations = new ArrayList<>();
        associations.add("a");
        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
                .thenReturn(associations);
        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());

        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);