Fix PendingIntent hijacking for adb notifications.
Use an explicit intent and set PendingIntent.FLAG_IMMUTABLE to prevent
someone from modifying the intent from PendingIntent.send(...).
Bug: 153356209
Test: atest AdbNotificationsTest
Test: In bug, install and launch the PoC apk and give it notification
permissions. Then, with USB/Wifi debugging enabled, disconnect and connect
the device to create the adb notification. the PoC apk should not have
permission to display information from
content://com.android.settings.files/my_cache/NOTICE.html.
Change-Id: Ie49aa3cf9b33168cf1435fc2427e95aac7f4609b
(cherry picked from commit 2c03881459)
Exempt-From-Owner-Approval: approved in master
This commit is contained in:
90
core/java/android/debug/AdbNotifications.java
Normal file
90
core/java/android/debug/AdbNotifications.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.debug;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.notification.SystemNotificationChannels;
|
||||
|
||||
/**
|
||||
* Utility class for building adb notifications.
|
||||
* @hide
|
||||
*/
|
||||
public final class AdbNotifications {
|
||||
/**
|
||||
* Notification channel for tv types.
|
||||
*/
|
||||
private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
|
||||
|
||||
/**
|
||||
* Builds a notification to show connected state for adb over a transport type.
|
||||
* @param context the context
|
||||
* @param transportType the adb transport type.
|
||||
* @return a newly created Notification for the transport type.
|
||||
*/
|
||||
public static Notification createNotification(@NonNull Context context,
|
||||
byte transportType) {
|
||||
Resources resources = context.getResources();
|
||||
int titleId;
|
||||
int messageId;
|
||||
|
||||
if (transportType == AdbTransportType.USB) {
|
||||
titleId = com.android.internal.R.string.adb_active_notification_title;
|
||||
messageId = com.android.internal.R.string.adb_active_notification_message;
|
||||
} else if (transportType == AdbTransportType.WIFI) {
|
||||
titleId = com.android.internal.R.string.adbwifi_active_notification_title;
|
||||
messageId = com.android.internal.R.string.adbwifi_active_notification_message;
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"createNotification called with unknown transport type=" + transportType);
|
||||
}
|
||||
|
||||
CharSequence title = resources.getText(titleId);
|
||||
CharSequence message = resources.getText(messageId);
|
||||
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
intent.setPackage(context.getPackageManager().resolveActivity(intent,
|
||||
PackageManager.MATCH_SYSTEM_ONLY).activityInfo.packageName);
|
||||
PendingIntent pIntent = PendingIntent.getActivityAsUser(context, 0, intent,
|
||||
PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
|
||||
|
||||
return new Notification.Builder(context, SystemNotificationChannels.DEVELOPER_IMPORTANT)
|
||||
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
|
||||
.setWhen(0)
|
||||
.setOngoing(true)
|
||||
.setTicker(title)
|
||||
.setDefaults(0) // please be quiet
|
||||
.setColor(context.getColor(
|
||||
com.android.internal.R.color.system_notification_accent_color))
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setContentIntent(pIntent)
|
||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||
.extend(new Notification.TvExtender()
|
||||
.setChannelId(ADB_NOTIFICATION_CHANNEL_ID_TV))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,9 @@
|
||||
<!-- WindowMetricsTest permissions -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<!-- Allow use of PendingIntent.getIntent() -->
|
||||
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
|
||||
|
||||
<application android:theme="@style/Theme" android:supportsRtl="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false" />
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.debug;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
public final class AdbNotificationsTest {
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNotification_UsbTransportType() throws Exception {
|
||||
CharSequence title = mContext.getResources().getText(
|
||||
com.android.internal.R.string.adb_active_notification_title);
|
||||
CharSequence message = mContext.getResources().getText(
|
||||
com.android.internal.R.string.adb_active_notification_message);
|
||||
|
||||
Notification notification = AdbNotifications.createNotification(mContext,
|
||||
AdbTransportType.USB);
|
||||
|
||||
// Verify that the adb notification for usb connections has the correct text.
|
||||
assertEquals(title, notification.extras.getCharSequence(Notification.EXTRA_TITLE, ""));
|
||||
assertEquals(message, notification.extras.getCharSequence(Notification.EXTRA_TEXT, ""));
|
||||
// Verify the PendingIntent has an explicit intent (b/153356209).
|
||||
assertFalse(TextUtils.isEmpty(notification.contentIntent.getIntent().getPackage()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNotification_WifiTransportType() throws Exception {
|
||||
CharSequence title = mContext.getResources().getText(
|
||||
com.android.internal.R.string.adbwifi_active_notification_title);
|
||||
CharSequence message = mContext.getResources().getText(
|
||||
com.android.internal.R.string.adbwifi_active_notification_message);
|
||||
|
||||
Notification notification = AdbNotifications.createNotification(mContext,
|
||||
AdbTransportType.WIFI);
|
||||
|
||||
// Verify that the adb notification for usb connections has the correct text.
|
||||
assertEquals(title, notification.extras.getCharSequence(Notification.EXTRA_TITLE, ""));
|
||||
assertEquals(message, notification.extras.getCharSequence(Notification.EXTRA_TEXT, ""));
|
||||
// Verify the PendingIntent has an explicit intent (b/153356209).
|
||||
assertFalse(TextUtils.isEmpty(notification.contentIntent.getIntent().getPackage()));
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import android.app.ActivityManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@@ -36,6 +35,7 @@ import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.debug.AdbManager;
|
||||
import android.debug.AdbNotifications;
|
||||
import android.debug.AdbProtoEnums;
|
||||
import android.debug.AdbTransportType;
|
||||
import android.debug.PairDevice;
|
||||
@@ -69,7 +69,6 @@ import android.util.Xml;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
||||
import com.android.internal.notification.SystemNotificationChannels;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
@@ -760,40 +759,13 @@ public class AdbDebuggingManager {
|
||||
// Show when at least one device is connected.
|
||||
public void showAdbConnectedNotification(boolean show) {
|
||||
final int id = SystemMessage.NOTE_ADB_WIFI_ACTIVE;
|
||||
final int titleRes = com.android.internal.R.string.adbwifi_active_notification_title;
|
||||
if (show == mAdbNotificationShown) {
|
||||
return;
|
||||
}
|
||||
setupNotifications();
|
||||
if (!mAdbNotificationShown) {
|
||||
Resources r = mContext.getResources();
|
||||
CharSequence title = r.getText(titleRes);
|
||||
CharSequence message = r.getText(
|
||||
com.android.internal.R.string.adbwifi_active_notification_message);
|
||||
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
|
||||
intent, 0, null, UserHandle.CURRENT);
|
||||
|
||||
Notification notification =
|
||||
new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
|
||||
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
|
||||
.setWhen(0)
|
||||
.setOngoing(true)
|
||||
.setTicker(title)
|
||||
.setDefaults(0) // please be quiet
|
||||
.setColor(mContext.getColor(
|
||||
com.android.internal.R.color
|
||||
.system_notification_accent_color))
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setContentIntent(pi)
|
||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||
.extend(new Notification.TvExtender()
|
||||
.setChannelId(ADB_NOTIFICATION_CHANNEL_ID_TV))
|
||||
.build();
|
||||
Notification notification = AdbNotifications.createNotification(mContext,
|
||||
AdbTransportType.WIFI);
|
||||
mAdbNotificationShown = true;
|
||||
mNotificationManager.notifyAsUser(null, id, notification,
|
||||
UserHandle.ALL);
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.debug.AdbManagerInternal;
|
||||
import android.debug.AdbNotifications;
|
||||
import android.debug.AdbTransportType;
|
||||
import android.debug.IAdbTransport;
|
||||
import android.hardware.usb.ParcelableUsbPort;
|
||||
@@ -1180,7 +1181,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
protected void updateAdbNotification(boolean force) {
|
||||
if (mNotificationManager == null) return;
|
||||
final int id = SystemMessage.NOTE_ADB_ACTIVE;
|
||||
final int titleRes = com.android.internal.R.string.adb_active_notification_title;
|
||||
|
||||
if (isAdbEnabled() && mConnected) {
|
||||
if ("0".equals(getSystemProperty("persist.adb.notify", ""))) return;
|
||||
@@ -1191,38 +1191,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
}
|
||||
|
||||
if (!mAdbNotificationShown) {
|
||||
Resources r = mContext.getResources();
|
||||
CharSequence title = r.getText(titleRes);
|
||||
CharSequence message = r.getText(
|
||||
com.android.internal.R.string.adb_active_notification_message);
|
||||
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
|
||||
intent, 0, null, UserHandle.CURRENT);
|
||||
|
||||
Notification notification =
|
||||
new Notification.Builder(mContext,
|
||||
SystemNotificationChannels.DEVELOPER_IMPORTANT)
|
||||
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
|
||||
.setWhen(0)
|
||||
.setOngoing(true)
|
||||
.setTicker(title)
|
||||
.setDefaults(0) // please be quiet
|
||||
.setColor(mContext.getColor(
|
||||
com.android.internal.R.color
|
||||
.system_notification_accent_color))
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setContentIntent(pi)
|
||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||
.extend(new Notification.TvExtender()
|
||||
.setChannelId(ADB_NOTIFICATION_CHANNEL_ID_TV))
|
||||
.build();
|
||||
Notification notification = AdbNotifications.createNotification(mContext,
|
||||
AdbTransportType.USB);
|
||||
mAdbNotificationShown = true;
|
||||
mNotificationManager.notifyAsUser(null, id, notification,
|
||||
UserHandle.ALL);
|
||||
mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL);
|
||||
}
|
||||
} else if (mAdbNotificationShown) {
|
||||
mAdbNotificationShown = false;
|
||||
|
||||
Reference in New Issue
Block a user