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

Commit 8cc3c6e5 authored by Matías Hernández's avatar Matías Hernández Committed by Mohammed Althaf T
Browse files

Prevent accidental creation of PackagePreferences for non-existing packages

This could be caused by (indirectly) invoking PreferencesHelper.getOrCreatePackagePreferences with an INVALID_UID (e.g. as the result of NMS passing along the result of getUidForPackageAndUser for a missing package). This was never intended -- API calls can result in the creation of PackagePreferences (since the structure is lazily initialized) but only for present packages. In most cases this was prevented by other checks (e.g. canNotifyAsPackage, which fails if missing) but specifically for the "fromPrivilegedListener" methods there was no similar enforcement.

Switch the PreferencesHelper usage so that:
* setters (e.g. create/updateChannel, groups) throw if supplied an invalid uid.
* getters that should have PackagePreferences creation as a side effect (e.g. getChannel) early exit if supplied an invalid uid.
* most getters don't actually create PackagePreferences and just return default values (e.g. canShowBadge) if they don't exist yet.

(Also, unify constants for representing a missing package into Process.INVALID_UID, and fix several tests that were impropely set up).

Bug: 426207912
Test: atest NotificationManagerServiceTest PreferencesHelperTest
(cherry picked from commit 236cff68)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:a629bb1b5e87dbcd82a0ab85c681f443b606ce10
Merged-In: I7d0717aed9fb26490f68801c9220833f2bed8e23
Change-Id: I7d0717aed9fb26490f68801c9220833f2bed8e23
parent 846f35f7
Loading
Loading
Loading
Loading
+27 −15
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.INVALID_UID;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -394,7 +395,6 @@ public class NotificationManagerService extends SystemService {
    static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
    static final int INVALID_UID = -1;
    static final String ROOT_PKG = "root";
    static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
@@ -3967,7 +3967,7 @@ public class NotificationManagerService extends SystemService {
                String conversationId) {
            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
                    || isCallerIsSystemOrSysemUiOrShell()) {
                int targetUid = -1;
                int targetUid = INVALID_UID;
                try {
                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
                } catch (NameNotFoundException e) {
@@ -4200,7 +4200,7 @@ public class NotificationManagerService extends SystemService {
                String callingPkg, String targetPkg, int userId) {
            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
                || isCallingUidSystem()) {
                int targetUid = -1;
                int targetUid = INVALID_UID;
                try {
                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
                } catch (NameNotFoundException e) {
@@ -5798,14 +5798,12 @@ public class NotificationManagerService extends SystemService {
        }
        private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
            int uid = INVALID_UID;
            final long identity = Binder.clearCallingIdentity();
            try {
                uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
                return mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
            return uid;
        }
        @Override
@@ -11605,15 +11603,22 @@ public class NotificationManagerService extends SystemService {
            List<UserHandle> users = mUm.getUserHandles(/* excludeDying */ true);
            mNonBlockableDefaultApps = new ArrayMap<>();
            for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
                String role = NON_BLOCKABLE_DEFAULT_ROLES[i];
                final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
                mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
                mNonBlockableDefaultApps.put(role, userToApprovedList);
                for (int j = 0; j < users.size(); j++) {
                    Integer userId = users.get(j).getIdentifier();
                    int userId = users.get(j).getIdentifier();
                    ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
                            NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
                            role, UserHandle.of(userId)));
                    ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
                    for (String pkg : approvedForUserId) {
                        approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
                        int uid = getUidForPackage(pkg, userId);
                        if (uid != INVALID_UID) {
                            approvedAppUids.add(new Pair<>(pkg, uid));
                        } else {
                            Slog.e(TAG, "init: Invalid package for role " + role
                                    + " (user " + userId + "): " + pkg);
                        }
                    }
                    userToApprovedList.put(userId, approvedForUserId);
                    mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
@@ -11679,8 +11684,13 @@ public class NotificationManagerService extends SystemService {
            }
            for (String nowApproved : roleHolders) {
                if (!previouslyApproved.contains(nowApproved)) {
                    toAdd.add(new Pair(nowApproved,
                            getUidForPackage(nowApproved, user.getIdentifier())));
                    int uid = getUidForPackage(nowApproved, user.getIdentifier());
                    if (uid != INVALID_UID) {
                        toAdd.add(new Pair<>(nowApproved, uid));
                    } else {
                        Slog.e(TAG, "onRoleHoldersChanged: Invalid package for role " + roleName
                                + " (user " + user.getIdentifier() + "): " + nowApproved);
                    }
                }
            }
@@ -11720,10 +11730,12 @@ public class NotificationManagerService extends SystemService {
                UserHandle user = users[i];
                for (String pkg : mRm.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, user)) {
                    int uid = getUidForPackage(pkg, user.getIdentifier());
                    if (uid != -1) {
                    if (uid != INVALID_UID) {
                        newUids.add(uid);
                    } else {
                        Slog.e(TAG, "Bad uid (-1) for browser package " + pkg);
                        Slog.e(TAG, "updateTrampoline: Invalid package for role "
                                + RoleManager.ROLE_BROWSER + " (user " + user.getIdentifier()
                                + "): " + pkg);
                    }
                }
            }
@@ -11736,7 +11748,7 @@ public class NotificationManagerService extends SystemService {
            } catch (RemoteException e) {
                Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
            }
            return -1;
            return INVALID_UID;
        }
    }
+92 −79

File changed.

Preview size limit exceeded, changes collapsed.

+52 −0

File changed.

Preview size limit exceeded, changes collapsed.

+43 −38

File changed.

Preview size limit exceeded, changes collapsed.

+32 −1
Original line number Diff line number Diff line
@@ -25,12 +25,16 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.eq;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import static java.util.Arrays.asList;
@@ -50,6 +54,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.telecom.TelecomManager;
@@ -231,6 +236,32 @@ public class RoleObserverTest extends UiServiceTestCase {
        verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, emer0Pair);
    }

    @Test
    public void testInit_withInvalidPackages_invalidIgnored() throws Exception {
        UserHandle user = new UserHandle(0);
        when(mUm.getUserHandles(anyBoolean())).thenReturn(List.of(user));
        String invalidDialerPkg = "invalidDialer";
        String validEmergencyPkg = "emergency";
        doThrow(new RemoteException(new PackageManager.NameNotFoundException())).when(mPm)
                .getPackageUid(eq(invalidDialerPkg), anyLong(), eq(user.getIdentifier()));
        doReturn(40).when(mPm)
                .getPackageUid(eq(validEmergencyPkg), anyLong(), eq(user.getIdentifier()));
        when(mRoleManager.getRoleHoldersAsUser(ROLE_DIALER, user))
                .thenReturn(List.of(invalidDialerPkg));
        when(mRoleManager.getRoleHoldersAsUser(ROLE_EMERGENCY, user))
                .thenReturn(List.of(validEmergencyPkg));

        mRoleObserver.init();

        // Only valid packages were passed to PreferencesHelper
        ArraySet<Pair<String, Integer>> expectedEmergencyApps = new ArraySet<>();
        expectedEmergencyApps.add(new Pair<>(validEmergencyPkg, 40));
        ArraySet<Pair<String, Integer>> expectedDialerApps = new ArraySet<>();
        verify(mPreferencesHelper).updateDefaultApps(0, null, expectedEmergencyApps);
        verify(mPreferencesHelper).updateDefaultApps(0, null, expectedDialerApps);
        verifyNoMoreInteractions(mPreferencesHelper);
    }

    @Test
    public void testInit_forTrampolines() throws Exception {
        when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30);