fix(client): validate LSYN payload length before parsing remote layouts

fixes: #10107

A malicious server can send a language synchronisation (LSYN) message
with a single-byte payload. size()-2 then underflows to SIZE_MAX and
substr(2, 2) throws std::out_of_range, terminating the client.

Reject odd-length payloads before mutating state, mirroring the
existing DSOP even-length check; an empty payload is still treated as
a normal clear.
This commit is contained in:
wildoranges 2026-08-29 14:11:35 +08:00 committed by Chris Rizzitello
parent fac2f540c5
commit adb4f89453
3 changed files with 26 additions and 5 deletions

View file

@ -35,12 +35,15 @@ KeyboardLayoutManager::KeyboardLayoutManager(const std::vector<std::string> &loc
void KeyboardLayoutManager::setRemoteLayouts(const std::string_view &remoteLayouts) void KeyboardLayoutManager::setRemoteLayouts(const std::string_view &remoteLayouts)
{ {
if (!remoteLayouts.empty() && remoteLayouts.size() % 2 != 0) {
LOG_ERR("remote layouts are the incorrect size, can not process them");
return;
}
m_remoteLayouts.clear(); m_remoteLayouts.clear();
if (!remoteLayouts.empty()) { for (size_t i = 0; i + 2 <= remoteLayouts.size(); i += 2) {
for (size_t i = 0; i <= remoteLayouts.size() - 2; i += 2) { auto rLangs = remoteLayouts.substr(i, 2);
auto rLangs = remoteLayouts.substr(i, 2); m_remoteLayouts.emplace_back(rLangs);
m_remoteLayouts.emplace_back(rLangs);
}
} }
LOG_INFO("remote layouts: %s", vectorToString(m_remoteLayouts, ", ").c_str()); LOG_INFO("remote layouts: %s", vectorToString(m_remoteLayouts, ", ").c_str());
} }

View file

@ -26,6 +26,22 @@ void KeyboardLayoutManagerTests::remoteLayouts()
QVERIFY(manager.getRemoteLayouts().empty()); QVERIFY(manager.getRemoteLayouts().empty());
} }
void KeyboardLayoutManagerTests::remoteLayouts_tooShort_returnsEmpty()
{
deskflow::KeyboardLayoutManager manager({"ru", "en", "uk"});
manager.setRemoteLayouts("a");
QVERIFY(manager.getRemoteLayouts().empty());
}
void KeyboardLayoutManagerTests::remoteLayouts_oddLength_returnsEmpty()
{
deskflow::KeyboardLayoutManager manager({"ru", "en", "uk"});
manager.setRemoteLayouts("rue");
QVERIFY(manager.getRemoteLayouts().empty());
}
void KeyboardLayoutManagerTests::localLayout() void KeyboardLayoutManagerTests::localLayout()
{ {
std::vector<std::string> localLayouts = {"ru", "en", "uk"}; std::vector<std::string> localLayouts = {"ru", "en", "uk"};

View file

@ -15,6 +15,8 @@ private Q_SLOTS:
void initTestCase(); void initTestCase();
// Test are run in order top to bottom // Test are run in order top to bottom
void remoteLayouts(); void remoteLayouts();
void remoteLayouts_tooShort_returnsEmpty();
void remoteLayouts_oddLength_returnsEmpty();
void localLayout(); void localLayout();
void missedLayout(); void missedLayout();
void serializeLocalLayouts(); void serializeLocalLayouts();