Skip to content
Snippets Groups Projects
Commit 71cfb89a authored by Valentin Iftime's avatar Valentin Iftime Committed by Iavor-Valentin Iftime
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
Change-Id: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
(cherry picked from commit 9b7bbbf5)
Merged-In: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
parent 2373dd64
No related branches found
No related tags found
No related merge requests found
......@@ -5744,6 +5744,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);
}
 
......@@ -5835,6 +5839,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();
......
......@@ -3592,6 +3592,69 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
}
 
@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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment