|
|
|
|
@ -88,8 +88,102 @@ namespace KWin |
|
|
|
|
|
|
|
|
|
KWIN_SINGLETON_FACTORY(WaylandServer) |
|
|
|
|
|
|
|
|
|
class KWinDisplay : public KWaylandServer::FilteredDisplay |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
KWinDisplay(QObject *parent) |
|
|
|
|
: KWaylandServer::FilteredDisplay(parent) |
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
static QByteArray sha256(const QString &fileName) |
|
|
|
|
{ |
|
|
|
|
QFile f(fileName); |
|
|
|
|
if (f.open(QFile::ReadOnly)) { |
|
|
|
|
QCryptographicHash hash(QCryptographicHash::Sha256); |
|
|
|
|
if (hash.addData(&f)) { |
|
|
|
|
return hash.result(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return QByteArray(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool isTrustedOrigin(KWaylandServer::ClientConnection *client) const { |
|
|
|
|
const auto fullPathSha = sha256(client->executablePath()); |
|
|
|
|
const auto localSha = sha256(QLatin1String("/proc/") + QString::number(client->processId()) + QLatin1String("/exe")); |
|
|
|
|
const bool trusted = !localSha.isEmpty() && fullPathSha == localSha; |
|
|
|
|
|
|
|
|
|
if (!trusted) { |
|
|
|
|
qCWarning(KWIN_CORE) << "Could not trust" << client->executablePath() << "sha" << localSha << fullPathSha; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return trusted; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QStringList fetchRequestedInterfaces(KWaylandServer::ClientConnection *client) const { |
|
|
|
|
return KWin::fetchRequestedInterfaces(client->executablePath()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const QSet<QByteArray> interfacesBlackList = {"org_kde_kwin_remote_access_manager", "org_kde_plasma_window_management", "org_kde_kwin_fake_input", "org_kde_kwin_keystate", "zkde_screencast_unstable_v1"}; |
|
|
|
|
|
|
|
|
|
const QSet<QByteArray> inputmethodInterfaces = { "zwp_input_panel_v1", "zwp_input_method_v1" }; |
|
|
|
|
|
|
|
|
|
QSet<QString> m_reported; |
|
|
|
|
|
|
|
|
|
bool allowInterface(KWaylandServer::ClientConnection *client, const QByteArray &interfaceName) override { |
|
|
|
|
if (client->processId() == getpid()) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (client != waylandServer()->inputMethodConnection() && inputmethodInterfaces.contains(interfaceName)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!interfacesBlackList.contains(interfaceName)) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (client->executablePath().isEmpty()) { |
|
|
|
|
qCWarning(KWIN_CORE) << "Could not identify process with pid" << client->processId(); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
auto requestedInterfaces = client->property("requestedInterfaces"); |
|
|
|
|
if (requestedInterfaces.isNull()) { |
|
|
|
|
requestedInterfaces = fetchRequestedInterfaces(client); |
|
|
|
|
client->setProperty("requestedInterfaces", requestedInterfaces); |
|
|
|
|
} |
|
|
|
|
if (!requestedInterfaces.toStringList().contains(QString::fromUtf8(interfaceName))) { |
|
|
|
|
if (KWIN_CORE().isDebugEnabled()) { |
|
|
|
|
const QString id = client->executablePath() + QLatin1Char('|') + QString::fromUtf8(interfaceName); |
|
|
|
|
if (!m_reported.contains({id})) { |
|
|
|
|
m_reported.insert(id); |
|
|
|
|
qCDebug(KWIN_CORE) << "Interface" << interfaceName << "not in X-KDE-Wayland-Interfaces of" << client->executablePath(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
auto trustedOrigin = client->property("isPrivileged"); |
|
|
|
|
if (trustedOrigin.isNull()) { |
|
|
|
|
trustedOrigin = isTrustedOrigin(client); |
|
|
|
|
client->setProperty("isPrivileged", trustedOrigin); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!trustedOrigin.toBool()) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
qCDebug(KWIN_CORE) << "authorized" << client->executablePath() << interfaceName; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
WaylandServer::WaylandServer(QObject *parent) |
|
|
|
|
: QObject(parent) |
|
|
|
|
, m_display(new KWinDisplay(this)) |
|
|
|
|
{ |
|
|
|
|
qRegisterMetaType<KWaylandServer::OutputInterface::DpmsMode>(); |
|
|
|
|
} |
|
|
|
|
@ -136,11 +230,9 @@ void WaylandServer::terminateClientConnections() |
|
|
|
|
{ |
|
|
|
|
destroyInternalConnection(); |
|
|
|
|
destroyInputMethodConnection(); |
|
|
|
|
if (m_display) { |
|
|
|
|
const auto connections = m_display->connections(); |
|
|
|
|
for (auto it = connections.begin(); it != connections.end(); ++it) { |
|
|
|
|
(*it)->destroy(); |
|
|
|
|
} |
|
|
|
|
const auto connections = m_display->connections(); |
|
|
|
|
for (auto it = connections.begin(); it != connections.end(); ++it) { |
|
|
|
|
(*it)->destroy(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -233,99 +325,6 @@ AbstractWaylandOutput *WaylandServer::findOutput(KWaylandServer::OutputInterface |
|
|
|
|
return outputFound; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class KWinDisplay : public KWaylandServer::FilteredDisplay |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
KWinDisplay(QObject *parent) |
|
|
|
|
: KWaylandServer::FilteredDisplay(parent) |
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
static QByteArray sha256(const QString &fileName) |
|
|
|
|
{ |
|
|
|
|
QFile f(fileName); |
|
|
|
|
if (f.open(QFile::ReadOnly)) { |
|
|
|
|
QCryptographicHash hash(QCryptographicHash::Sha256); |
|
|
|
|
if (hash.addData(&f)) { |
|
|
|
|
return hash.result(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return QByteArray(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool isTrustedOrigin(KWaylandServer::ClientConnection *client) const { |
|
|
|
|
const auto fullPathSha = sha256(client->executablePath()); |
|
|
|
|
const auto localSha = sha256(QLatin1String("/proc/") + QString::number(client->processId()) + QLatin1String("/exe")); |
|
|
|
|
const bool trusted = !localSha.isEmpty() && fullPathSha == localSha; |
|
|
|
|
|
|
|
|
|
if (!trusted) { |
|
|
|
|
qCWarning(KWIN_CORE) << "Could not trust" << client->executablePath() << "sha" << localSha << fullPathSha; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return trusted; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QStringList fetchRequestedInterfaces(KWaylandServer::ClientConnection *client) const { |
|
|
|
|
return KWin::fetchRequestedInterfaces(client->executablePath()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const QSet<QByteArray> interfacesBlackList = {"org_kde_kwin_remote_access_manager", "org_kde_plasma_window_management", "org_kde_kwin_fake_input", "org_kde_kwin_keystate", "zkde_screencast_unstable_v1"}; |
|
|
|
|
|
|
|
|
|
const QSet<QByteArray> inputmethodInterfaces = { "zwp_input_panel_v1", "zwp_input_method_v1" }; |
|
|
|
|
|
|
|
|
|
QSet<QString> m_reported; |
|
|
|
|
|
|
|
|
|
bool allowInterface(KWaylandServer::ClientConnection *client, const QByteArray &interfaceName) override { |
|
|
|
|
if (client->processId() == getpid()) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (client != waylandServer()->inputMethodConnection() && inputmethodInterfaces.contains(interfaceName)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!interfacesBlackList.contains(interfaceName)) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (client->executablePath().isEmpty()) { |
|
|
|
|
qCWarning(KWIN_CORE) << "Could not identify process with pid" << client->processId(); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
auto requestedInterfaces = client->property("requestedInterfaces"); |
|
|
|
|
if (requestedInterfaces.isNull()) { |
|
|
|
|
requestedInterfaces = fetchRequestedInterfaces(client); |
|
|
|
|
client->setProperty("requestedInterfaces", requestedInterfaces); |
|
|
|
|
} |
|
|
|
|
if (!requestedInterfaces.toStringList().contains(QString::fromUtf8(interfaceName))) { |
|
|
|
|
if (KWIN_CORE().isDebugEnabled()) { |
|
|
|
|
const QString id = client->executablePath() + QLatin1Char('|') + QString::fromUtf8(interfaceName); |
|
|
|
|
if (!m_reported.contains({id})) { |
|
|
|
|
m_reported.insert(id); |
|
|
|
|
qCDebug(KWIN_CORE) << "Interface" << interfaceName << "not in X-KDE-Wayland-Interfaces of" << client->executablePath(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
auto trustedOrigin = client->property("isPrivileged"); |
|
|
|
|
if (trustedOrigin.isNull()) { |
|
|
|
|
trustedOrigin = isTrustedOrigin(client); |
|
|
|
|
client->setProperty("isPrivileged", trustedOrigin); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!trustedOrigin.toBool()) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
qCDebug(KWIN_CORE) << "authorized" << client->executablePath() << interfaceName; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
bool WaylandServer::start() |
|
|
|
|
{ |
|
|
|
|
return m_display->start(); |
|
|
|
|
|