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] 905c0a341d

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
This commit is contained in:
Kai Uwe Broulik 2022-08-16 16:07:50 +02:00 committed by Kai Uwe Broulik
parent 3646620430
commit 50ae65809e
2 changed files with 12 additions and 22 deletions

View file

@ -10,7 +10,6 @@
#include "surface_interface.h"
#include "utils/common.h"
// Qt
#include <QTemporaryFile>
#include <QVector>
#include <unistd.h>
@ -74,28 +73,15 @@ void KeyboardInterfacePrivate::sendEnter(SurfaceInterface *surface, quint32 seri
void KeyboardInterfacePrivate::sendKeymap(Resource *resource)
{
std::unique_ptr<QTemporaryFile> 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<char *>(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) {

View file

@ -6,6 +6,7 @@
#pragma once
#include "keyboard_interface.h"
#include "utils/ramfile.h"
#include <qwayland-server-wayland.h>
@ -38,6 +39,7 @@ public:
SurfaceInterface *focusedSurface = nullptr;
QMetaObject::Connection destroyConnection;
QByteArray keymap;
KWin::RamFile sharedKeymapFile;
struct
{