From c8c33ae3987083d347015ebc006ff997f1a5f229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 10 Feb 2016 16:43:06 +0100 Subject: [PATCH] Implement lock screen security for touch events When the screen gets locked any existing sequence gets cancelled and the focused touch surface gets reset. While screen is locked touch events are filtered to only go to lock screen or input methods. Test case is added for touch event during lock screen. Reviewed-By: Bhushan Shah --- autotests/wayland/lockscreen.cpp | 40 ++++++++++++++++++++++++ input.cpp | 53 ++++++++++++++++++++++++++++++++ input.h | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/autotests/wayland/lockscreen.cpp b/autotests/wayland/lockscreen.cpp index 831503d94e..fa722f22e9 100644 --- a/autotests/wayland/lockscreen.cpp +++ b/autotests/wayland/lockscreen.cpp @@ -38,6 +38,7 @@ along with this program. If not, see . #include #include #include +#include //screenlocker #include @@ -68,6 +69,7 @@ private Q_SLOTS: void testAxisShortcut_data(); void testAxisShortcut(); void testKeyboardShortcut(); + void testTouch(); private: void unlock(); @@ -725,6 +727,44 @@ void LockScreenTest::testKeyboardShortcut() KEYRELEASE(KEY_LEFTALT); } +void LockScreenTest::testTouch() +{ + using namespace KWayland::Client; + auto touch = m_seat->createTouch(m_seat); + QVERIFY(touch); + QVERIFY(touch->isValid()); + AbstractClient *c = showWindow(); + QVERIFY(c); + QSignalSpy sequenceStartedSpy(touch, &Touch::sequenceStarted); + QVERIFY(sequenceStartedSpy.isValid()); + QSignalSpy cancelSpy(touch, &Touch::sequenceCanceled); + QVERIFY(cancelSpy.isValid()); + QSignalSpy pointRemovedSpy(touch, &Touch::pointRemoved); + QVERIFY(pointRemovedSpy.isValid()); + + quint32 timestamp = 1; + waylandServer()->backend()->touchDown(1, QPointF(25, 25), timestamp++); + QVERIFY(sequenceStartedSpy.wait()); + QCOMPARE(sequenceStartedSpy.count(), 1); + + LOCK + QVERIFY(cancelSpy.wait()); + + waylandServer()->backend()->touchUp(1, timestamp++); + QVERIFY(!pointRemovedSpy.wait(100)); + waylandServer()->backend()->touchDown(1, QPointF(25, 25), timestamp++); + waylandServer()->backend()->touchMotion(1, QPointF(26, 26), timestamp++); + waylandServer()->backend()->touchUp(1, timestamp++); + + UNLOCK + waylandServer()->backend()->touchDown(1, QPointF(25, 25), timestamp++); + QVERIFY(sequenceStartedSpy.wait()); + QCOMPARE(sequenceStartedSpy.count(), 2); + waylandServer()->backend()->touchUp(1, timestamp++); + QVERIFY(pointRemovedSpy.wait()); + QCOMPARE(pointRemovedSpy.count(), 1); +} + } WAYLANTEST_MAIN(KWin::LockScreenTest) diff --git a/input.cpp b/input.cpp index c501261e8c..31672192e5 100644 --- a/input.cpp +++ b/input.cpp @@ -403,6 +403,49 @@ public: } return true; } + bool touchDown(quint32 id, const QPointF &pos, quint32 time) { + if (!waylandServer()->isScreenLocked()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + if (!seat->isTouchSequence()) { + input()->updateTouchWindow(pos); + } + if (touchSurfaceAllowed()) { + input()->insertTouchId(id, seat->touchDown(pos)); + } + return true; + } + bool touchMotion(quint32 id, const QPointF &pos, quint32 time) { + if (!waylandServer()->isScreenLocked()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + if (touchSurfaceAllowed()) { + const qint32 kwaylandId = input()->touchId(id); + if (kwaylandId != -1) { + seat->touchMove(kwaylandId, pos); + } + } + return true; + } + bool touchUp(quint32 id, quint32 time) { + if (!waylandServer()->isScreenLocked()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + if (touchSurfaceAllowed()) { + const qint32 kwaylandId = input()->touchId(id); + if (kwaylandId != -1) { + seat->touchUp(kwaylandId); + input()->removeTouchId(id); + } + } + return true; + } private: bool surfaceAllowed(KWayland::Server::SurfaceInterface *(KWayland::Server::SeatInterface::*method)() const) const { if (KWayland::Server::SurfaceInterface *s = (waylandServer()->seat()->*method)()) { @@ -419,6 +462,9 @@ private: bool keyboardSurfaceAllowed() const { return surfaceAllowed(&KWayland::Server::SeatInterface::focusedKeyboardSurface); } + bool touchSurfaceAllowed() const { + return surfaceAllowed(&KWayland::Server::SeatInterface::focusedTouchSurface); + } }; class EffectsFilter : public InputEventFilter { @@ -872,6 +918,13 @@ void InputRedirection::setupWorkspace() connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &InputRedirection::updatePointerWindow); connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &InputRedirection::updateKeyboardWindow); + connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, + [this] { + cancelTouch(); + // position doesn't matter + updateTouchWindow(QPointF()); + } + ); } setupInputFilters(); } diff --git a/input.h b/input.h index 5820228d6f..10cbb8fea8 100644 --- a/input.h +++ b/input.h @@ -156,6 +156,7 @@ public: void removeTouchId(quint32 internalId); void updateKeyboardWindow(); + void updateTouchWindow(const QPointF &pos); public Q_SLOTS: void updatePointerWindow(); @@ -209,7 +210,6 @@ private: void registerShortcutForGlobalAccelTimestamp(QAction *action); void updateFocusedPointerPosition(); void updateFocusedTouchPosition(); - void updateTouchWindow(const QPointF &pos); void updatePointerDecoration(Toplevel *t); void updatePointerInternalWindow(); void pointerInternalWindowVisibilityChanged(bool visible);