Loading services/core/java/com/android/server/notification/NotificationManagerService.java +22 −0 Original line number Diff line number Diff line Loading @@ -5556,6 +5556,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); } Loading Loading @@ -5635,6 +5639,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(); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +67 −0 Original line number Diff line number Diff line Loading @@ -2646,6 +2646,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); Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +22 −0 Original line number Diff line number Diff line Loading @@ -5556,6 +5556,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); } Loading Loading @@ -5635,6 +5639,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(); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +67 −0 Original line number Diff line number Diff line Loading @@ -2646,6 +2646,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); Loading