diff options
author | Iván Budnik <ivanbuper@google.com> | 2023-04-04 17:58:26 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-16 08:30:43 +0000 |
commit | 0cd003717465df3749fe360fe1241392b0935a41 (patch) | |
tree | 31d0bade06e2259f2aade88afc6c242139272459 | |
parent | 27971d20c92c9a0c66af6ff60c37e9f8e3c9cee2 (diff) | |
download | base-0cd003717465df3749fe360fe1241392b0935a41.tar.gz |
Validate ComponentName for MediaButtonBroadcastReceiver
This is a security fix for b/270049379.
Bug: 270049379
Test: atest CtsMediaMiscTestCases
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c573c83a2aa36ca022302f675d705518dd723a3c)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ba546a306217389a8ff9e5e948612651fd496081)
Merged-In: I05626f7abf1efef86c9e01ee3f077d7177d7f662
Change-Id: I05626f7abf1efef86c9e01ee3f077d7177d7f662
-rw-r--r-- | media/java/android/media/session/MediaSession.java | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/media/MediaSessionRecord.java | 33 |
2 files changed, 38 insertions, 3 deletions
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 84ecc06d172f..09eff9e4e13a 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -297,9 +297,11 @@ public final class MediaSession { * class that should receive media buttons. This allows restarting playback after the session * has been stopped. If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} * intent will be sent to the broadcast receiver. - * <p> - * Note: The given {@link android.content.BroadcastReceiver} should belong to the same package - * as the context that was given when creating {@link MediaSession}. + * + * <p>Note: The given {@link android.content.BroadcastReceiver} should belong to the same + * package as the context that was given when creating {@link MediaSession}. + * + * <p>Calls with invalid or non-existent receivers will be ignored. * * @param broadcastReceiver the component name of the BroadcastReceiver class */ diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 1bd50632ccbf..cc4895ffaf24 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -16,12 +16,17 @@ package com.android.server.media; +import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; +import android.content.pm.ResolveInfo; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioSystem; @@ -52,6 +57,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; +import android.os.UserHandle; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; @@ -884,6 +890,22 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } }; + @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) + private static boolean componentNameExists( + @NonNull ComponentName componentName, @NonNull Context context, int userId) { + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + mediaButtonIntent.setComponent(componentName); + + UserHandle userHandle = UserHandle.of(userId); + PackageManager pm = context.getPackageManager(); + + List<ResolveInfo> resolveInfos = + pm.queryBroadcastReceiversAsUser( + mediaButtonIntent, /* flags */ 0, userHandle); + return !resolveInfos.isEmpty(); + } + private final class SessionStub extends ISession.Stub { @Override public void destroySession() throws RemoteException { @@ -954,6 +976,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } @Override + @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) public void setMediaButtonBroadcastReceiver(ComponentName receiver) throws RemoteException { final long token = Binder.clearCallingIdentity(); try { @@ -969,6 +992,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR != 0) { return; } + + if (!componentNameExists(receiver, mContext, mUserId)) { + Log.w( + TAG, + "setMediaButtonBroadcastReceiver(): " + + "Ignoring invalid component name=" + + receiver); + return; + } + mMediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mUserId, receiver); mService.onMediaButtonReceiverChanged(MediaSessionRecord.this); } finally { |