From d207589897fc20ad852406a24211d88dda46cda6 Mon Sep 17 00:00:00 2001 From: Michal Karpinski Date: Wed, 17 Apr 2019 16:01:10 +0100 Subject: [PATCH] Make sure Notification#deleteIntent cannot be used to start activities from background Remove whitelisting privilege from deleteIntent before it's sent in cancelNotificationLocked(). Bug: 130619912 Test: manual (with a custom built app that provides PendingIntent.getActivity() to Notification.Builder.setDeleteIntent()) Change-Id: I8a85b4c32717f958c4ee2fe040b73bceb96d7feb --- core/java/android/app/ActivityManagerInternal.java | 7 +++++++ .../java/com/android/server/am/ActivityManagerService.java | 13 +++++++++++++ .../java/com/android/server/am/PendingIntentRecord.java | 7 +++++++ .../server/notification/NotificationManagerService.java | 9 +++++++-- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index e8d32932503b..500a04fc7be5 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -80,6 +80,13 @@ public abstract class ActivityManagerInternal { IIntentSender target, IBinder whitelistToken, int flags); /** + * Voids {@link PendingIntent}'s privilege to be whitelisted to start activities from + * background. + */ + public abstract void clearPendingIntentAllowBgActivityStarts(IIntentSender target, + IBinder whitelistToken); + + /** * Allow DeviceIdleController to tell us about what apps are whitelisted. */ public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3b6b404170c5..d759a495fa8e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17578,6 +17578,19 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void clearPendingIntentAllowBgActivityStarts(IIntentSender target, + IBinder whitelistToken) { + if (!(target instanceof PendingIntentRecord)) { + Slog.w(TAG, "clearPendingIntentAllowBgActivityStarts():" + + " not a PendingIntentRecord: " + target); + return; + } + synchronized (ActivityManagerService.this) { + ((PendingIntentRecord) target).clearAllowBgActivityStarts(whitelistToken); + } + } + + @Override public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) { synchronized (ActivityManagerService.this) { mDeviceIdleWhitelist = allAppids; diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 588e05d7a060..acddb4772f86 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -236,6 +236,13 @@ public final class PendingIntentRecord extends IIntentSender.Stub { } } + void clearAllowBgActivityStarts(IBinder token) { + if (token == null) return; + mAllowBgActivityStartsForActivitySender.remove(token); + mAllowBgActivityStartsForBroadcastSender.remove(token); + mAllowBgActivityStartsForServiceSender.remove(token); + } + public void registerCancelListenerLocked(IResultReceiver receiver) { if (mCancelCallbacks == null) { mCancelCallbacks = new RemoteCallbackList<>(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 042ac8c5760e..24f513ed0b8c 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6335,9 +6335,14 @@ public class NotificationManagerService extends SystemService { // tell the app if (sendDelete) { - if (r.getNotification().deleteIntent != null) { + final PendingIntent deleteIntent = r.getNotification().deleteIntent; + if (deleteIntent != null) { try { - r.getNotification().deleteIntent.send(); + // make sure deleteIntent cannot be used to start activities from background + LocalServices.getService(ActivityManagerInternal.class) + .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(), + WHITELIST_TOKEN); + deleteIntent.send(); } catch (PendingIntent.CanceledException ex) { // do nothing - there's no relevant way to recover, and // no reason to let this propagate -- 2.11.0