Add new MotionEvent flag for partially obscured windows.

Due to more complex window layouts resulting in lots of overlapping
windows, the policy around FLAG_WINDOW_IS_OBSCURED has changed to
only be set when the point at which the window was touched is
obscured. Unfortunately, this doesn't prevent tapjacking attacks that
overlay the dialog's text, making a potentially dangerous operation
seem innocuous. To avoid this on particularly sensitive dialogs,
introduce a new flag that really does tell you when your window is
being even partially overlapped.

We aren't exposing this as API since we plan on making the original
flag more robust. This is really a workaround for system dialogs
since we generally know their layout and screen position, and that
they're unlikely to be overlapped by other applications.

Bug: 26677796
Change-Id: I9e336afe90f262ba22015876769a9c510048fd47
This commit is contained in:
Michael Wright 2016-03-22 16:52:13 -07:00 committed by The Android Automerger
parent a59b827869
commit 03a53d1c77
5 changed files with 61 additions and 3 deletions

View File

@ -45,6 +45,19 @@ enum {
}; };
enum { enum {
/**
* This flag indicates that the window that received this motion event is partly
* or wholly obscured by another visible window above it. This flag is set to true
* even if the event did not directly pass through the obscured area.
* A security sensitive application can check this flag to identify situations in which
* a malicious application may have covered up part of its content for the purpose
* of misleading the user or hijacking touches. An appropriate response might be
* to drop the suspect touches or to take additional precautions to confirm the user's
* actual intent.
*/
AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2,
/* Motion event is inconsistent with previously sent motion events. */ /* Motion event is inconsistent with previously sent motion events. */
AMOTION_EVENT_FLAG_TAINTED = 0x80000000, AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
}; };

View File

@ -1225,6 +1225,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(windowHandle)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
} }
mTempTouchState.addOrUpdateWindow( mTempTouchState.addOrUpdateWindow(
@ -1262,6 +1264,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
} }
if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
} }
// Update hover state. // Update hover state.
@ -1437,6 +1441,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
== InputWindowInfo::TYPE_WALLPAPER) { == InputWindowInfo::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(windowHandle, mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED InputTarget::FLAG_WINDOW_IS_OBSCURED
| InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS, | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0)); BitSet32(0));
} }
@ -1631,6 +1636,27 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(
return false; return false;
} }
bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
int32_t displayId = windowHandle->getInfo()->displayId;
const InputWindowInfo* windowInfo = windowHandle->getInfo();
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
if (otherHandle == windowHandle) {
break;
}
const InputWindowInfo* otherInfo = otherHandle->getInfo();
if (otherInfo->displayId == displayId
&& otherInfo->visible && !otherInfo->isTrustedOverlay()
&& otherInfo->overlaps(windowInfo)) {
return true;
}
}
return false;
}
String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
const char* targetType) { const char* targetType) {
@ -1905,6 +1931,9 @@ void InputDispatcher::enqueueDispatchEntryLocked(
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
} }
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
if (!connection->inputState.trackMotion(motionEntry, if (!connection->inputState.trackMotion(motionEntry,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {

View File

@ -89,7 +89,7 @@ struct InputTarget {
/* This flag indicates that the event is being delivered to a foreground application. */ /* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0, FLAG_FOREGROUND = 1 << 0,
/* This flag indicates that the target of a MotionEvent is partly or wholly /* This flag indicates that the MotionEvent falls within the area of the target
* obscured by another visible window above it. The motion event should be * obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
FLAG_WINDOW_IS_OBSCURED = 1 << 1, FLAG_WINDOW_IS_OBSCURED = 1 << 1,
@ -139,6 +139,12 @@ struct InputTarget {
| FLAG_DISPATCH_AS_HOVER_EXIT | FLAG_DISPATCH_AS_HOVER_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_ENTER, | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
}; };
// The input channel to be targeted. // The input channel to be targeted.
@ -1048,6 +1054,7 @@ private:
const InjectionState* injectionState); const InjectionState* injectionState);
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
int32_t x, int32_t y) const; int32_t x, int32_t y) const;
bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle); const sp<InputWindowHandle>& windowHandle);

View File

@ -36,14 +36,16 @@ bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
} }
bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight return x >= frameLeft && x < frameRight
&& y >= frameTop && y <= frameBottom; && y >= frameTop && y < frameBottom;
} }
bool InputWindowInfo::isTrustedOverlay() const { bool InputWindowInfo::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
|| layoutParamsType == TYPE_STATUS_BAR
|| layoutParamsType == TYPE_NAVIGATION_BAR
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
} }
@ -51,6 +53,11 @@ bool InputWindowInfo::supportsSplitTouch() const {
return layoutParamsFlags & FLAG_SPLIT_TOUCH; return layoutParamsFlags & FLAG_SPLIT_TOUCH;
} }
bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
return frameLeft < other->frameRight && frameRight > other->frameLeft
&& frameTop < other->frameBottom && frameBottom > other->frameTop;
}
// --- InputWindowHandle --- // --- InputWindowHandle ---

View File

@ -146,6 +146,8 @@ struct InputWindowInfo {
bool isTrustedOverlay() const; bool isTrustedOverlay() const;
bool supportsSplitTouch() const; bool supportsSplitTouch() const;
bool overlaps(const InputWindowInfo* other) const;
}; };