From 076e8ba2537c752e8eaddf016b677b81f0b5bcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 3 Jun 2016 12:42:59 +0200 Subject: [PATCH] [server] Trigger error if a transient request tries to parent to itself Summary: If the surface passed in the transient request is to the surface of the shell surface, KWin aborts. It's an obvious invalid request, so handle it properly by sending an error. Reviewers: #plasma Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D1755 --- src/wayland/autotests/client/test_error.cpp | 24 +++++++++++++++++++++ src/wayland/server/shell_interface.cpp | 9 ++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/wayland/autotests/client/test_error.cpp b/src/wayland/autotests/client/test_error.cpp index e57c2efa1c..a4f82cbf15 100644 --- a/src/wayland/autotests/client/test_error.cpp +++ b/src/wayland/autotests/client/test_error.cpp @@ -42,6 +42,8 @@ private Q_SLOTS: void cleanup(); void testMultipleShellSurfacesForSurface(); + void testTransientForSameSurface_data(); + void testTransientForSameSurface(); private: Display *m_display = nullptr; @@ -143,5 +145,27 @@ void ErrorTest::testMultipleShellSurfacesForSurface() QCOMPARE(m_connection->errorCode(), EPROTO); } +void ErrorTest::testTransientForSameSurface_data() +{ + QTest::addColumn("flag"); + + QTest::newRow("transient") << ShellSurface::TransientFlag::Default; + QTest::newRow("transient no focus") << ShellSurface::TransientFlag::NoFocus; +} + +void ErrorTest::testTransientForSameSurface() +{ + // this test verifies that creating a transient shell surface for itself triggers a protocol error + QSignalSpy errorSpy(m_connection, &ConnectionThread::errorOccurred); + QVERIFY(errorSpy.isValid()); + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer shellSurface(m_shell->createSurface(surface.data())); + QFETCH(ShellSurface::TransientFlag, flag); + shellSurface->setTransient(surface.data(), QPoint(), flag); + QVERIFY(errorSpy.wait()); + QVERIFY(m_connection->hasError()); + QCOMPARE(m_connection->errorCode(), EPROTO); +} + QTEST_GUILESS_MAIN(ErrorTest) #include "test_error.moc" diff --git a/src/wayland/server/shell_interface.cpp b/src/wayland/server/shell_interface.cpp index 07725eb50e..37f88f3488 100644 --- a/src/wayland/server/shell_interface.cpp +++ b/src/wayland/server/shell_interface.cpp @@ -147,7 +147,7 @@ void ShellInterface::Private::createSurface(wl_client *client, uint32_t version, } ); if (it != surfaces.constEnd()) { - wl_resource_post_error(surface->resource(), WL_DISPLAY_ERROR_INVALID_OBJECT, "ShellSurface already created"); + wl_resource_post_error(surface->resource(), WL_SHELL_ERROR_ROLE, "ShellSurface already created"); return; } ShellSurfaceInterface *shellSurface = new ShellSurfaceInterface(q, surface, parentResource); @@ -312,7 +312,12 @@ void ShellSurfaceInterface::Private::setTransientCallback(wl_client *client, wl_ Q_UNUSED(flags) auto s = cast(resource); Q_ASSERT(client == *s->client); - s->transientFor = QPointer(SurfaceInterface::get(parent)); + auto surface = SurfaceInterface::get(parent); + if (surface && s->surface == surface) { + wl_resource_post_error(surface->resource(), WL_SHELL_ERROR_ROLE, "Cannot be a transient to itself"); + return; + } + s->transientFor = QPointer(surface); s->transientOffset = QPoint(x, y); emit s->q_func()->transientChanged(!s->transientFor.isNull()); emit s->q_func()->transientOffsetChanged(s->transientOffset);