summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Budnik <ivanbuper@google.com>2023-04-04 17:58:26 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-06-14 00:37:23 +0000
commitde0b6c36d30d7fa7196b0f8a28d855c270a8fd63 (patch)
treebf3ba5d229ac9631e3c61cacc3264953e76450f5
parente2ee0f86ab8c2c0c2ac34709282b9d52a6344be5 (diff)
downloadbase-de0b6c36d30d7fa7196b0f8a28d855c270a8fd63.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.java8
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java33
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 {