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

Commit 7317ad55 authored by youngmin0822.lee's avatar youngmin0822.lee Committed by bkchoi
Browse files

Validate the user is allowed to set UiMode

UiMode is basically managed for the current user, and there were code
locations in UiModeManagerService that make assumptions of the
requesting user being the current user.
If non-current user attempts to set UiMode, the current user's UiMode
may be changed.
For example, in 'multi-user on multiple displays' mode in Automotive,
the passenger access may be mistaken as the driver access, and it leads
to interferes with the driver experience.
To fix this, verify the calling user to ensure that only valid user can
set the mode.

Bug: 319554832
Test: atest CtsAppTestCases:UiModeManagerTest
(cherry picked from
https://partner-android-review.git.corp.google.com/q/commit:41f6fb5cc5aac722c342b4d71b73415f78fc3f71)

Change-Id: I9c9defd7966f453962f4190d2778777ec27bf110
parent a5777368
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.getCallingUserId;
import static android.os.UserManager.isVisibleBackgroundUsersEnabled;
import static android.provider.Settings.Secure.CONTRAST_LEVEL;
import static android.util.TimeUtils.isTimeBetween;

@@ -99,6 +100,7 @@ import com.android.internal.app.DisableCarModeActivity;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.DumpUtils;
import com.android.server.pm.UserManagerService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -848,6 +850,8 @@ final class UiModeManagerService extends SystemService {
            }

            final int user = UserHandle.getCallingUserId();
            enforceValidCallingUser(user);

            final long ident = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
@@ -910,6 +914,8 @@ final class UiModeManagerService extends SystemService {
                @AttentionModeThemeOverlayType int attentionModeThemeOverlayType) {
            setAttentionModeThemeOverlay_enforcePermission();

            enforceValidCallingUser(UserHandle.getCallingUserId());

            synchronized (mLock) {
                if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) {
                    mAttentionModeThemeOverlay = attentionModeThemeOverlayType;
@@ -999,6 +1005,8 @@ final class UiModeManagerService extends SystemService {
                return false;
            }
            final int user = Binder.getCallingUserHandle().getIdentifier();
            enforceValidCallingUser(user);

            if (user != mCurrentUser && getContext().checkCallingOrSelfPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS)
                    != PackageManager.PERMISSION_GRANTED) {
@@ -1056,6 +1064,8 @@ final class UiModeManagerService extends SystemService {
                return;
            }
            final int user = UserHandle.getCallingUserId();
            enforceValidCallingUser(user);

            final long ident = Binder.clearCallingIdentity();
            try {
                LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000);
@@ -1084,6 +1094,8 @@ final class UiModeManagerService extends SystemService {
                return;
            }
            final int user = UserHandle.getCallingUserId();
            enforceValidCallingUser(user);

            final long ident = Binder.clearCallingIdentity();
            try {
                LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000);
@@ -1104,6 +1116,8 @@ final class UiModeManagerService extends SystemService {
            assertLegit(callingPackage);
            assertSingleProjectionType(projectionType);
            enforceProjectionTypePermissions(projectionType);
            enforceValidCallingUser(getCallingUserId());

            synchronized (mLock) {
                if (mProjectionHolders == null) {
                    mProjectionHolders = new SparseArray<>(1);
@@ -1148,6 +1162,8 @@ final class UiModeManagerService extends SystemService {
            assertLegit(callingPackage);
            assertSingleProjectionType(projectionType);
            enforceProjectionTypePermissions(projectionType);
            enforceValidCallingUser(getCallingUserId());

            return releaseProjectionUnchecked(projectionType, callingPackage);
        }

@@ -1187,6 +1203,9 @@ final class UiModeManagerService extends SystemService {
            if (projectionType == PROJECTION_TYPE_NONE) {
                return;
            }

            enforceValidCallingUser(getCallingUserId());

            synchronized (mLock) {
                if (mProjectionListeners == null) {
                    mProjectionListeners = new SparseArray<>(1);
@@ -1234,6 +1253,32 @@ final class UiModeManagerService extends SystemService {
        }
    };

    // This method validates whether calling user is valid in visible background users
    // feature. Valid user is the current user or the system or in the same profile group as
    // the current user.
    private void enforceValidCallingUser(int userId) {
        if (!isVisibleBackgroundUsersEnabled()) {
            return;
        }
        if (LOG) {
            Slog.d(TAG, "enforceValidCallingUser: userId=" + userId
                    + " isSystemUser=" + (userId == USER_SYSTEM) + " current user=" + mCurrentUser
                    + " callingPid=" + Binder.getCallingPid()
                    + " callingUid=" + mInjector.getCallingUid());
        }
        long ident = Binder.clearCallingIdentity();
        try {
            if (userId != USER_SYSTEM && userId != mCurrentUser
                    && !UserManagerService.getInstance().isSameProfileGroup(userId, mCurrentUser)) {
                throw new SecurityException(
                        "Calling user is not valid for level-1 compatibility in MUMD. "
                                + "callingUserId=" + userId + " currentUserId=" + mCurrentUser);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    private void enforceProjectionTypePermissions(@UiModeManager.ProjectionType int p) {
        if ((p & PROJECTION_TYPE_AUTOMOTIVE) != 0) {
            getContext().enforceCallingPermission(