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

Commit d6c80db0 authored by Surbhi Kadam's avatar Surbhi Kadam Committed by mse1969
Browse files

[BACKPORT] Sanitize window private flags based on caller permissions.

Introduces `sanitizePrivateFlags` to check if the calling application has the necessary permissions to set certain `LayoutParams.privateFlags`. Specifically, `PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY` and `PRIVATE_FLAG_TRUSTED_OVERLAY` require `INTERNAL_SYSTEM_WINDOW`, and `PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP` requires `MANAGE_ACTIVITY_TASKS`. These flags are removed if the caller lacks the required permissions during window relayout.

Bug: 406243581
Test: atest WindowManagerServiceTests
Flag: EXEMPT bug fix

(cherry picked from commit ec6a92be)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:de831dc7ee8d95de5568cd981f82b92f1fc29f0a
Merged-In: I4fdf2152f06082e13690e7f5b628e0ca0acdff84
Change-Id: I4fdf2152f06082e13690e7f5b628e0ca0acdff84
parent 3500ece0
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -2158,6 +2158,8 @@ public class WindowManagerService extends IWindowManager.Stub
            if (attrs != null) {
                displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
                win.mToken.adjustWindowParams(win, attrs);
                attrs.privateFlags = sanitizePrivateFlags(attrs.privateFlags,
                        win.mAttrs.privateFlags, win.getName(), uid, pid);
                attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), uid, pid);
                // if they don't have the permission, mask out the status bar bits
                if (seq == win.mSeq) {
@@ -8080,6 +8082,35 @@ public class WindowManagerService extends IWindowManager.Stub
        return flags;
    }

    private boolean hasFlags(int flags, int mask) {
        return (flags & mask) != 0;
    }

    private boolean hasPermission(String permission, int callingPid, int callingUid) {
        return mContext.checkPermission(permission, callingPid, callingUid)
                == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * Ensure the caller has the right permissions to be able to set the requested private flags.
     */
    private int sanitizePrivateFlags(int newPrivateFlags, int oldPrivateFlags, String windowName,
            int callingUid, int callingPid) {
        final int addedPrivateFlags = ~oldPrivateFlags & newPrivateFlags;
        int sanitizedFlags = newPrivateFlags;
        if (hasFlags(addedPrivateFlags,
                (PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY| PRIVATE_FLAG_TRUSTED_OVERLAY))
                && !hasPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW,
                    callingUid, callingPid)) {
            Slog.w(TAG, "Removing PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY or"
                    + " PRIVATE_FLAG_TRUSTED_OVERLAY from '" + windowName
                    + "' because it doesn't have INTERNAL_SYSTEM_WINDOW permission");
            sanitizedFlags &=
                    ~(PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY | PRIVATE_FLAG_TRUSTED_OVERLAY);
        }
        return sanitizedFlags;
    }

    /**
     * Assigns an InputChannel to a SurfaceControl and configures it to receive
     * touch input according to it's on-screen geometry.
+169 −0
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
@@ -166,4 +169,170 @@ public class WindowManagerServiceTests extends WindowTestsBase {

        verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
    }

    @Test
    public void testRelayout_addTrustedOverlay_permissionDenied() {
        testRelayoutFlagChanges(
                false, /* firstRelayout */
                0, /* startFlags */
                0, /* startPrivateFlags */
                0, /* newFlags */
                PRIVATE_FLAG_TRUSTED_OVERLAY, /* newPrivateFlags */
                0, /* expectedChangedFlags */
                0, /* expectedChangedPrivateFlags */
                0, /* expectedFlagsValue */
                0, /* expectedPrivateFlagsValue */
                false, /* internalSystemWindowGranted */
                true /* manageActivityTasksGranted */);
    }

    @Test
    public void testRelayout_addTrustedOverlay_permissionGranted() {
        testRelayoutFlagChanges(
                false, /* firstRelayout */
                0, /* startFlags */
                0, /* startPrivateFlags */
                0, /* newFlags */
                PRIVATE_FLAG_TRUSTED_OVERLAY, /* newPrivateFlags */
                0, /* expectedChangedFlags */
                PRIVATE_FLAG_TRUSTED_OVERLAY, /* expectedChangedPrivateFlags */
                0, /* expectedFlagsValue */
                PRIVATE_FLAG_TRUSTED_OVERLAY /* expectedPrivateFlagsValue */,
                true, /* internalSystemWindowGranted */
                true /* manageActivityTasksGranted */);
    }

    @Test
    public void testRelayout_addRoundedCornersOverlay_permissionDenied() {
        testRelayoutFlagChanges(
                false, /* firstRelayout */
                0, /* startFlags */
                0, /* startPrivateFlags */
                0, /* newFlags */
                PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY, /* newPrivateFlags */
                0, /* expectedChangedFlags */
                0, /* expectedChangedPrivateFlags */
                0, /* expectedFlagsValue */
                0, /* expectedPrivateFlagsValue */
                false, /* internalSystemWindowGranted */
                true /* manageActivityTasksGranted */);
    }

    @Test
    public void testRelayout_addRoundedCornersOverlay_permissionGranted() {
        testRelayoutFlagChanges(
                false, /* firstRelayout */
                0, /* startFlags */
                0, /* startPrivateFlags */
                0, /* newFlags */
                PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY, /* newPrivateFlags */
                0, /* expectedChangedFlags */
                PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY, /* expectedChangedPrivateFlags */
                0, /* expectedFlagsValue */
                PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY /* expectedPrivateFlagsValue */,
                true, /* internalSystemWindowGranted */
                true /* manageActivityTasksGranted */);
    }

    @Test
    public void testRelayout_addInterceptGlobalDragAndDrop_permissionDenied() {
        testRelayoutFlagChanges(
                false, /* firstRelayout */
                0, /* startFlags */
                0, /* startPrivateFlags */
                0, /* newFlags */
                PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP, /* newPrivateFlags */
                0, /* expectedChangedFlags */
                0, /* expectedChangedPrivateFlags */
                0, /* expectedFlagsValue */
                0, /* expectedPrivateFlagsValue */
                true, /* internalSystemWindowGranted */
                false /* manageActivityTasksGranted */);
    }

    @Test
    public void testRelayout_addInterceptGlobalDragAndDrop_permissionGranted() {
        testRelayoutFlagChanges(
                false, /* firstRelayout */
                0, /* startFlags */
                0, /* startPrivateFlags */
                0, /* newFlags */
                PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP, /* newPrivateFlags */
                0, /* expectedChangedFlags */
                PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP, /* expectedChangedPrivateFlags */
                0, /* expectedFlagsValue */
                PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP /* expectedPrivateFlagsValue */,
                true, /* internalSystemWindowGranted */
                true /* manageActivityTasksGranted */);
    }


    private void testRelayoutFlagChanges(boolean firstRelayout, int startFlags,
            int startPrivateFlags, int newFlags, int newPrivateFlags, int expectedChangedFlags,
            int expectedChangedPrivateFlags, int expectedFlagsValue,
            int expectedPrivateFlagsValue) {
            testRelayoutFlagChanges(firstRelayout, startFlags, startPrivateFlags, newFlags,
                    newPrivateFlags, expectedChangedFlags, expectedChangedPrivateFlags,
                    expectedFlagsValue, expectedPrivateFlagsValue,
                    true /* internalSystemWindowGranted */,
                    true /* manageActivityTasksGranted */);
    }

    // Helper method to test relayout of a window, either for the initial layout, or a subsequent
    // one, and makes sure that the flags and private flags changes and final values are properly
    // reported to mDwpcHelper.keepActivityOnWindowFlagsChanged.
    private void testRelayoutFlagChanges(boolean firstRelayout, int startFlags,
            int startPrivateFlags, int newFlags, int newPrivateFlags, int expectedChangedFlags,
            int expectedChangedPrivateFlags, int expectedFlagsValue,
            int expectedPrivateFlagsValue, boolean internalSystemWindowGranted,
            boolean manageActivityTasksGranted) {
        final WindowState win = newWindowBuilder("appWin", TYPE_BASE_APPLICATION).build();
        win.mRelayoutCalled = !firstRelayout;
        mWm.mWindowMap.put(win.mClient.asBinder(), win);
        spyOn(mDisplayContent.mDwpcHelper);
        when(mDisplayContent.mDwpcHelper.hasController()).thenReturn(true);

        doReturn(internalSystemWindowGranted ? PackageManager.PERMISSION_GRANTED
                : PackageManager.PERMISSION_DENIED).when(mWm.mContext).checkPermission(
                eq(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW), anyInt(), anyInt());
        doReturn(manageActivityTasksGranted ? PackageManager.PERMISSION_GRANTED
                : PackageManager.PERMISSION_DENIED).when(mWm.mContext).checkPermission(
                eq(android.Manifest.permission.MANAGE_ACTIVITY_TASKS), anyInt(), anyInt());

        win.mAttrs.flags = startFlags;
        win.mAttrs.privateFlags = startPrivateFlags;

        LayoutParams newParams = new LayoutParams();
        newParams.copyFrom(win.mAttrs);
        newParams.flags = newFlags;
        newParams.privateFlags = newPrivateFlags;

        int seq = 1;
        if (!firstRelayout) {
            win.mRelayoutSeq = 1;
            seq = 2;
        }
        mWm.relayoutWindow(win.mSession, win.mClient, newParams, 100, 200, View.VISIBLE, 0, seq,
                0, new WindowRelayoutResult(), new SurfaceControl());

        ArgumentCaptor<Integer> changedFlags = ArgumentCaptor.forClass(Integer.class);
        ArgumentCaptor<Integer> changedPrivateFlags = ArgumentCaptor.forClass(Integer.class);
        ArgumentCaptor<Integer> flagsValue = ArgumentCaptor.forClass(Integer.class);
        ArgumentCaptor<Integer> privateFlagsValue = ArgumentCaptor.forClass(Integer.class);

        if (!firstRelayout && expectedChangedFlags == 0 && expectedChangedPrivateFlags == 0) {
            verify(mDisplayContent.mDwpcHelper, never()).keepActivityOnWindowFlagsChanged(
                    any(ActivityInfo.class), anyInt(), anyInt(), anyInt(), anyInt());
            return;
        }

        verify(mDisplayContent.mDwpcHelper).keepActivityOnWindowFlagsChanged(
                any(ActivityInfo.class), changedFlags.capture(), changedPrivateFlags.capture(),
                flagsValue.capture(), privateFlagsValue.capture());

        assertThat(changedFlags.getValue()).isEqualTo(expectedChangedFlags);
        assertThat(changedPrivateFlags.getValue()).isEqualTo(expectedChangedPrivateFlags);
        assertThat(flagsValue.getValue()).isEqualTo(expectedFlagsValue);
        assertThat(privateFlagsValue.getValue()).isEqualTo(expectedPrivateFlagsValue);
    }
}