Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b663487d authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Look for apps in the proper user

System server can post notifications that appear to
be coming from apps in other users (like when apps in
a work profile start a foreground service). Thus,
when resolving the uid of the notification, it's not safe
to use the calling user; instead the userid as resolved
by ActivityManager.handleIncomingUser() must be used.

Test: runtest systemui-notification
Test: start a foreground service in a managed profile for
an app that doesn't exist in the primary user.
Fixes: 116283798
Bug: 116019760

Change-Id: I568f1ed6fabe64a6c32ef0901f76b2baadc63f6c
parent e36375ec
Loading
Loading
Loading
Loading
+14 −10
Original line number Diff line number Diff line
@@ -4284,8 +4284,12 @@ public class NotificationManagerService extends SystemService {
    @VisibleForTesting
    int resolveNotificationUid(String callingPkg, String targetPkg,
            int callingUid, int userId) {
        if (userId == UserHandle.USER_ALL) {
            userId = USER_SYSTEM;
        }
        // posted from app A on behalf of app A
        if (isCallerSameApp(targetPkg, callingUid) && TextUtils.equals(callingPkg, targetPkg)) {
        if (isCallerSameApp(targetPkg, callingUid, userId)
                && TextUtils.equals(callingPkg, targetPkg)) {
            return callingUid;
        }

@@ -4322,7 +4326,7 @@ public class NotificationManagerService extends SystemService {
        if (!isSystemNotification && !isNotificationFromListener) {
            synchronized (mNotificationLock) {
                if (mNotificationsByKey.get(r.sbn.getKey()) == null
                        && isCallerInstantApp(pkg, callingUid)) {
                        && isCallerInstantApp(pkg, callingUid, r.getUserId())) {
                    // Ephemeral apps have some special constraints for notifications.
                    // They are not allowed to create new notifications however they are allowed to
                    // update notifications created by the system (e.g. a foreground service
@@ -6416,7 +6420,8 @@ public class NotificationManagerService extends SystemService {
        }
    }

    private boolean isCallerInstantApp(String pkg, int callingUid) {
    @VisibleForTesting
    boolean isCallerInstantApp(String pkg, int callingUid, int userId) {
        // System is always allowed to act for ephemeral apps.
        if (isUidSystemOrPhone(callingUid)) {
            return false;
@@ -6425,8 +6430,7 @@ public class NotificationManagerService extends SystemService {
        mAppOps.checkPackage(callingUid, pkg);

        try {
            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
                    UserHandle.getCallingUserId());
            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
            if (ai == null) {
                throw new SecurityException("Unknown package " + pkg);
            }
@@ -6438,13 +6442,13 @@ public class NotificationManagerService extends SystemService {
    }

    private void checkCallerIsSameApp(String pkg) {
        checkCallerIsSameApp(pkg, Binder.getCallingUid());
        checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
    }

    private void checkCallerIsSameApp(String pkg, int uid) {
    private void checkCallerIsSameApp(String pkg, int uid, int userId) {
        try {
            ApplicationInfo ai = mPackageManager.getApplicationInfo(
                    pkg, 0, UserHandle.getCallingUserId());
                    pkg, 0, userId);
            if (ai == null) {
                throw new SecurityException("Unknown package " + pkg);
            }
@@ -6466,9 +6470,9 @@ public class NotificationManagerService extends SystemService {
        }
    }

    private boolean isCallerSameApp(String pkg, int uid) {
    private boolean isCallerSameApp(String pkg, int uid, int userId) {
        try {
            checkCallerIsSameApp(pkg, uid);
            checkCallerIsSameApp(pkg, uid, userId);
            return true;
        } catch (SecurityException e) {
            return false;
+35 −1
Original line number Diff line number Diff line
@@ -3382,11 +3382,45 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                anyString(), anyString(), anyInt());
    }

    @Test
    public void testIsCallerInstantApp_primaryUser() throws Exception {
        ApplicationInfo info = new ApplicationInfo();
        info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);

        assertTrue(mService.isCallerInstantApp("any", 45770, 0));

        info.privateFlags = 0;
        assertFalse(mService.isCallerInstantApp("any", 575370, 0));
    }

    @Test
    public void testIsCallerInstantApp_secondaryUser() throws Exception {
        ApplicationInfo info = new ApplicationInfo();
        info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);

        assertTrue(mService.isCallerInstantApp("any", 68638450, 10));
    }

    @Test
    public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception {
        ApplicationInfo info = new ApplicationInfo();
        info.uid = Binder.getCallingUid();
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);

        int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10);

        assertEquals(info.uid, actualUid);
    }

    @Test
    public void testResolveNotificationUid_sameApp() throws Exception {
        ApplicationInfo info = new ApplicationInfo();
        info.uid = Binder.getCallingUid();
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);

        int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);