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

Commit f48bf9a2 authored by Taran Singh's avatar Taran Singh Committed by Android Build Coastguard Worker
Browse files

DO NOT MERGE: Verify KeyEvents in IME

Malicious app can inject fabricated InputEvents into IME's FD which can
do tinker with special shortcuts like switching IME.
With this CL, all KeyEvents with modifiers OR indicated sensitive by IME will be
verified before being dispatched to IME.

For any events that are replayed, verify timestamp.

Bug: 331730488
Test: atest CtsInputMethodTestCases InputMethodServiceTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8d730cf69b864336fd492c88049efc937fac6b61)
Merged-In: I6589cc73839acb6b2c3f9256c664b5db7e1ade8a
Change-Id: I6589cc73839acb6b2c3f9256c664b5db7e1ade8a
parent 3c1515f4
Loading
Loading
Loading
Loading
+33 −2
Original line number Original line Diff line number Diff line
@@ -19,9 +19,11 @@ package android.inputmethodservice;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.InputChannel;
import android.view.InputChannel;
@@ -41,6 +43,8 @@ import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.SomeArgs;


import java.util.Objects;

class IInputMethodSessionWrapper extends IInputMethodSession.Stub
class IInputMethodSessionWrapper extends IInputMethodSession.Stub
        implements HandlerCaller.Callback {
        implements HandlerCaller.Callback {
    private static final String TAG = "InputMethodWrapper";
    private static final String TAG = "InputMethodWrapper";
@@ -56,6 +60,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
    private static final int DO_REMOVE_IME_SURFACE = 130;
    private static final int DO_REMOVE_IME_SURFACE = 130;
    private static final int DO_FINISH_INPUT = 140;
    private static final int DO_FINISH_INPUT = 140;
    private static final int DO_INVALIDATE_INPUT = 150;
    private static final int DO_INVALIDATE_INPUT = 150;
    private final Context mContext;




    @UnsupportedAppUsage
    @UnsupportedAppUsage
@@ -66,6 +71,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub


    public IInputMethodSessionWrapper(Context context,
    public IInputMethodSessionWrapper(Context context,
            InputMethodSession inputMethodSession, InputChannel channel) {
            InputMethodSession inputMethodSession, InputChannel channel) {
        mContext = context;
        mCaller = new HandlerCaller(context, null,
        mCaller = new HandlerCaller(context, null,
                this, true /*asyncHandler*/);
                this, true /*asyncHandler*/);
        mInputMethodSession = inputMethodSession;
        mInputMethodSession = inputMethodSession;
@@ -233,6 +239,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
    }
    }
    private final class ImeInputEventReceiver extends InputEventReceiver
    private final class ImeInputEventReceiver extends InputEventReceiver
            implements InputMethodSession.EventCallback {
            implements InputMethodSession.EventCallback {
        // Time after which a KeyEvent is invalid
        private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L;
        private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
        private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();


        public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
        public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
@@ -247,10 +255,23 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
                return;
                return;
            }
            }


            if (event instanceof KeyEvent keyEvent && hasKeyModifiers(keyEvent)) {
                // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that
                // they originated from system.
                InputManager im = mContext.getSystemService(InputManager.class);
                Objects.requireNonNull(im);
                final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime();
                if (age >= KEY_EVENT_ALLOW_PERIOD_MS || im.verifyInputEvent(keyEvent) == null) {
                    Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping "
                            + keyEvent);
                    finishInputEvent(event, false /* handled */);
                    return;
                }
            }

            final int seq = event.getSequenceNumber();
            final int seq = event.getSequenceNumber();
            mPendingEvents.put(seq, event);
            mPendingEvents.put(seq, event);
            if (event instanceof KeyEvent) {
            if (event instanceof KeyEvent keyEvent) {
                KeyEvent keyEvent = (KeyEvent)event;
                mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
                mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
            } else {
            } else {
                MotionEvent motionEvent = (MotionEvent)event;
                MotionEvent motionEvent = (MotionEvent)event;
@@ -271,5 +292,15 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
                finishInputEvent(event, handled);
                finishInputEvent(event, handled);
            }
            }
        }
        }

        private boolean hasKeyModifiers(KeyEvent event) {
            if (event.hasNoModifiers()) {
                return false;
            }
            return event.isCtrlPressed()
                    || event.isAltPressed()
                    || event.isFunctionPressed()
                    || event.isMetaPressed();
        }
    }
    }
}
}