From 50ae65809eb0dbeddbbfa16d223ff94b83f8877a Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Tue, 16 Aug 2022 16:07:50 +0200 Subject: [PATCH] keyboard_interface: Re-use the same keymap fd for supported clients This makes use of the new RamFile class to create a sealed anonymous file to pass the keymap information to clients. Since wl_seat version 7 [1] it is specified that clients must map the received fd as `MAP_PRIVATE`. This means we can use `SEAL_WRITE` on the file to prevent clients from tampering with it and subsequently reuse the same file for all clients using wl_seat version 7 or above. [1] https://gitlab.freedesktop.org/wayland/wayland/-/commit/905c0a341ddf0a885811d19e2b79c65a3f1d210c Signed-off-by: Victoria Fischer --- src/wayland/keyboard_interface.cpp | 32 ++++++++++-------------------- src/wayland/keyboard_interface_p.h | 2 ++ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/wayland/keyboard_interface.cpp b/src/wayland/keyboard_interface.cpp index 0a79af7368..9398956327 100644 --- a/src/wayland/keyboard_interface.cpp +++ b/src/wayland/keyboard_interface.cpp @@ -10,7 +10,6 @@ #include "surface_interface.h" #include "utils/common.h" // Qt -#include #include #include @@ -74,28 +73,15 @@ void KeyboardInterfacePrivate::sendEnter(SurfaceInterface *surface, quint32 seri void KeyboardInterfacePrivate::sendKeymap(Resource *resource) { - std::unique_ptr tmp(new QTemporaryFile()); - if (!tmp->open()) { - qCWarning(KWIN_CORE) << "Failed to create keymap file:" << tmp->errorString(); - return; + // From version 7 on, keymaps must be mapped privately, so that + // we can seal the fd and reuse it between clients. + if (resource->version() >= 7 && sharedKeymapFile.effectiveFlags().testFlag(KWin::RamFile::Flag::SealWrite)) { + send_keymap(resource->handle, keymap_format::keymap_format_xkb_v1, sharedKeymapFile.fd(), sharedKeymapFile.size()); + // otherwise give each client its own unsealed copy. + } else { + KWin::RamFile keymapFile("kwin-xkb-keymap", keymap.constData(), keymap.size() + 1); // Include QByteArray null-terminator. + send_keymap(resource->handle, keymap_format::keymap_format_xkb_v1, keymapFile.fd(), keymapFile.size()); } - - unlink(tmp->fileName().toUtf8().constData()); - if (!tmp->resize(keymap.size())) { - qCWarning(KWIN_CORE) << "Failed to resize keymap file:" << tmp->errorString(); - return; - } - - uchar *address = tmp->map(0, keymap.size()); - if (!address) { - qCWarning(KWIN_CORE) << "Failed to map keymap file:" << tmp->errorString(); - return; - } - - qstrncpy(reinterpret_cast(address), keymap.constData(), keymap.size() + 1); - tmp->unmap(address); - - send_keymap(resource->handle, keymap_format::keymap_format_xkb_v1, tmp->handle(), tmp->size()); } void KeyboardInterface::setKeymap(const QByteArray &content) @@ -105,6 +91,8 @@ void KeyboardInterface::setKeymap(const QByteArray &content) } d->keymap = content; + // +1 to include QByteArray null terminator. + d->sharedKeymapFile = KWin::RamFile("kwin-xkb-keymap-shared", content.constData(), content.size() + 1, KWin::RamFile::Flag::SealWrite); const auto keyboardResources = d->resourceMap(); for (KeyboardInterfacePrivate::Resource *resource : keyboardResources) { diff --git a/src/wayland/keyboard_interface_p.h b/src/wayland/keyboard_interface_p.h index bbde67d3f3..f54a1f8616 100644 --- a/src/wayland/keyboard_interface_p.h +++ b/src/wayland/keyboard_interface_p.h @@ -6,6 +6,7 @@ #pragma once #include "keyboard_interface.h" +#include "utils/ramfile.h" #include @@ -38,6 +39,7 @@ public: SurfaceInterface *focusedSurface = nullptr; QMetaObject::Connection destroyConnection; QByteArray keymap; + KWin::RamFile sharedKeymapFile; struct {