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

Commit ec6a92be authored by Surbhi Kadam's avatar Surbhi Kadam
Browse files

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

Change-Id: I4fdf2152f06082e13690e7f5b628e0ca0acdff84
parent 80c135d0
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -2506,6 +2506,8 @@ public class WindowManagerService extends IWindowManager.Stub
            int privateFlagChanges = 0;
            if (attrs != null) {
                displayPolicy.adjustWindowParamsLw(win, attrs);
                attrs.privateFlags = sanitizePrivateFlags(attrs.privateFlags,
                        win.mAttrs.privateFlags, win.getName(), uid, pid);
                attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), uid, pid);
                attrs.inputFeatures = sanitizeInputFeatures(attrs.inputFeatures, win.getName(), uid,
                        pid, win.isTrustedOverlay());
@@ -9614,6 +9616,42 @@ public class WindowManagerService extends IWindowManager.Stub
        return inputFeatures;
    }

    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);
        }
        if (hasFlags(addedPrivateFlags, LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP)
                && !hasPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS, callingUid,
                    callingPid)) {
            Slog.w(TAG, "Removing PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP from '"
                + windowName + "' because it doesn't have MANAGE_ACTIVITY_TASKS permission");
            sanitizedFlags &= ~LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
        }
        return sanitizedFlags;
    }

    /**
     * Assigns an InputChannel to a SurfaceControl and configures it to receive
     * touch input according to it's on-screen geometry.
+125 −1
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_DISPLAY_TOPO
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SENSITIVE_FOR_PRIVACY;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
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_APPLICATION_ATTACHED_DIALOG;
@@ -445,19 +447,135 @@ public class WindowManagerServiceTests extends WindowTestsBase {
                /*expectedPrivateFlagsValue=*/ 0);
    }

    @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) {
            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;

@@ -479,6 +597,12 @@ public class WindowManagerServiceTests extends WindowTestsBase {
        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());