| /* |
| * Copyright (C) 2023 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.security.cts.CVE_2023_21286; |
| |
| import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; |
| |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assume.assumeNoException; |
| import static org.junit.Assume.assumeTrue; |
| |
| import android.app.Instrumentation; |
| import android.app.Notification; |
| import android.app.NotificationChannel; |
| import android.app.NotificationManager; |
| import android.app.UiAutomation; |
| import android.content.Context; |
| import android.content.pm.UserInfo; |
| import android.graphics.drawable.Icon; |
| import android.net.Uri; |
| import android.os.UserManager; |
| import android.provider.MediaStore; |
| import android.widget.RemoteViews; |
| |
| import androidx.test.runner.AndroidJUnit4; |
| import androidx.test.uiautomator.By; |
| import androidx.test.uiautomator.UiDevice; |
| import androidx.test.uiautomator.UiObject2; |
| import androidx.test.uiautomator.Until; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.util.List; |
| |
| @RunWith(AndroidJUnit4.class) |
| public class DeviceTest { |
| |
| private AutoCloseable withAdoptShellPermissionIdentity( |
| UiAutomation uiAutomation, String permission) { |
| uiAutomation.adoptShellPermissionIdentity(permission); |
| |
| // Remove permissions |
| return () -> uiAutomation.dropShellPermissionIdentity(); |
| } |
| |
| @Test |
| public void testPocCVE_2023_21286() { |
| UiDevice uiDevice = null; |
| try { |
| final String cveId = "cve_2023_21286_"; |
| final String title = cveId + "title"; |
| |
| Instrumentation instrumentation = getInstrumentation(); |
| Context context = instrumentation.getContext(); |
| UiAutomation uiAutomation = instrumentation.getUiAutomation(); |
| uiDevice = UiDevice.getInstance(instrumentation); |
| int userId = -1; |
| |
| // Retrieve created user Id |
| try (AutoCloseable withAdoptShellPermissionIdentity = |
| withAdoptShellPermissionIdentity( |
| uiAutomation, android.Manifest.permission.CREATE_USERS)) { |
| final List<UserInfo> list = context.getSystemService(UserManager.class).getUsers(); |
| for (UserInfo info : list) { |
| if (info.name.contains(cveId)) { |
| userId = info.id; |
| break; |
| } |
| } |
| } |
| assumeTrue(userId != -1); |
| |
| // Post a notification with a content view containing image from other user |
| RemoteViews rvPortrait = |
| new RemoteViews(context.getPackageName(), R.layout.cve_2023_21286_layout); |
| rvPortrait.setImageViewUri( |
| R.id.cve_2023_21286_img, |
| Uri.parse("content://" + userId + "@media/external/images/media/")); |
| NotificationChannel notificationChannel = |
| new NotificationChannel(cveId, cveId, NotificationManager.IMPORTANCE_DEFAULT); |
| RemoteViews rvOuter = |
| new RemoteViews(context.getPackageName(), R.layout.cve_2023_21286_layout_outer); |
| rvOuter.addView(R.id.cve_2023_21286_outer, rvPortrait); |
| NotificationManager notificationManager = |
| context.getSystemService(NotificationManager.class); |
| notificationManager.createNotificationChannel(notificationChannel); |
| Notification notification = |
| new Notification.Builder(context, cveId) |
| .setContentTitle(title) |
| .setSmallIcon( |
| Icon.createWithData( |
| new byte[0] /* data */, 0 /* offset */, 0 /* length */)) |
| .setCustomContentView(rvOuter) |
| .setCustomBigContentView(rvOuter) |
| .build(); |
| try { |
| notificationManager.notify(0 /* id */, notification); |
| } catch (SecurityException securityException) { |
| if (securityException |
| .getLocalizedMessage() |
| .toLowerCase() |
| .contains(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) { |
| // Ignore exception thrown with fix and exit the test |
| return; |
| } else { |
| throw securityException; |
| } |
| } |
| |
| // Open notification shade |
| assumeTrue("Opening notification shade unsuccessful", uiDevice.openNotification()); |
| |
| // Wait for notification to appear and detect if the remote view is present |
| uiDevice.wait(Until.hasObject(By.text(title)), 3000 /* timeout */); |
| UiObject2 exposedImg = |
| uiDevice.findObject(By.res(context.getPackageName(), cveId + "img")); |
| assertNull( |
| "Device is vulnerable to b/277740082, Other user's images can be exposed in" |
| + " notifications using remote views", |
| exposedImg); |
| } catch (Exception e) { |
| assumeNoException(e); |
| } finally { |
| try { |
| uiDevice.pressHome(); |
| } catch (Exception e) { |
| // Ignore exceptions as the test has finished |
| } |
| } |
| } |
| } |