fix(cve): run switch commands as normal user on Windows to prevent privilege escalation
CVE-2026-41477
This commit is contained in:
parent
e7040a1f82
commit
5c480ca515
6 changed files with 89 additions and 9 deletions
|
|
@ -73,6 +73,7 @@ int main(int argc, char **argv)
|
|||
// It's important to write the version number to the log file so we can be certain the old daemon
|
||||
// was uninstalled, since sometimes Windows services can get stuck and fail to be removed.
|
||||
LOG_PRINT("%s v%s", qPrintable(QCoreApplication::applicationName()), kDisplayVersion);
|
||||
LOG_INFO("settings file: %s", qPrintable(Settings::settingsFile()));
|
||||
|
||||
// Default log level to system setting (found in Registry).
|
||||
auto logLevel = Settings::value(Settings::Daemon::LogLevel).toString().toStdString();
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ add_library(${lib_name} STATIC ${PLATFORM_CODE}
|
|||
|
||||
target_link_libraries(${lib_name} PUBLIC common Qt6::Core Qt6::Network)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${lib_name} PRIVATE platform)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(
|
||||
${lib_name}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,35 @@
|
|||
|
||||
#include <QProcess>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
#include "platform/MSWindowsProcess.h"
|
||||
#endif
|
||||
|
||||
namespace deskflow {
|
||||
|
||||
namespace {
|
||||
|
||||
bool runScreenCommand(const QString &commandLine)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
using deskflow::platform::MSWindowsProcess;
|
||||
if (ArchMiscWindows::isProcessElevated()) {
|
||||
LOG_DEBUG("current process is elevated, starting detached process as session user");
|
||||
return MSWindowsProcess::startDetachedAsSessionUser(commandLine.toStdWString());
|
||||
}
|
||||
#endif
|
||||
|
||||
auto args = QProcess::splitCommand(commandLine);
|
||||
if (args.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const auto program = args.takeFirst();
|
||||
return QProcess::startDetached(program, args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//
|
||||
// Screen
|
||||
//
|
||||
|
|
@ -123,10 +150,9 @@ void Screen::enter(KeyModifierMask toggleMask)
|
|||
}
|
||||
|
||||
if (Settings::value(Settings::Core::EnableEnterCommand).toBool()) {
|
||||
auto args = QProcess::splitCommand(Settings::value(Settings::Core::ScreenEnterCommand).toString());
|
||||
const auto command = args.takeFirst();
|
||||
LOG_DEBUG("running screen enter command: %s %s", qPrintable(command), qPrintable(args.join(" ")));
|
||||
if (!QProcess::startDetached(command, args))
|
||||
const auto commandLine = Settings::value(Settings::Core::ScreenEnterCommand).toString();
|
||||
LOG_DEBUG("running screen enter command: %s", qPrintable(commandLine));
|
||||
if (!runScreenCommand(commandLine))
|
||||
LOG_ERR("failed to run screen enter command");
|
||||
}
|
||||
}
|
||||
|
|
@ -151,10 +177,9 @@ bool Screen::leave()
|
|||
|
||||
m_screen->leave();
|
||||
if (Settings::value(Settings::Core::EnableExitCommand).toBool()) {
|
||||
auto args = QProcess::splitCommand(Settings::value(Settings::Core::ScreenExitCommand).toString());
|
||||
const auto command = args.takeFirst();
|
||||
LOG_DEBUG("running screen exit command: %s %s", qPrintable(command), qPrintable(args.join(" ")));
|
||||
if (!QProcess::startDetached(command, args))
|
||||
const auto commandLine = Settings::value(Settings::Core::ScreenExitCommand).toString();
|
||||
LOG_DEBUG("running screen exit command: %s", qPrintable(commandLine));
|
||||
if (!runScreenCommand(commandLine))
|
||||
LOG_ERR("failed to run screen exit command");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "base/Log.h"
|
||||
#include "common/Constants.h"
|
||||
#include "common/ExitCodes.h"
|
||||
#include "platform/MSWindowsSession.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
|
@ -188,6 +189,51 @@ void MSWindowsProcess::shutdown(HANDLE handle, DWORD pid, int timeout)
|
|||
}
|
||||
}
|
||||
|
||||
bool MSWindowsProcess::startDetachedAsSessionUser(const std::wstring &command)
|
||||
{
|
||||
MSWindowsSession session;
|
||||
session.updateActiveSession();
|
||||
|
||||
HANDLE userToken = nullptr;
|
||||
try {
|
||||
userToken = session.getUserToken(nullptr);
|
||||
} catch (const std::runtime_error &e) {
|
||||
LOG_ERR("could not get session user token: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
LPVOID environment = nullptr;
|
||||
if (!CreateEnvironmentBlock(&environment, userToken, FALSE)) {
|
||||
LOG_ERR("could not create environment block, error: %s", windowsErrorToString(GetLastError()).c_str());
|
||||
CloseHandle(userToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
STARTUPINFOW si = {};
|
||||
si.cb = sizeof(si);
|
||||
PROCESS_INFORMATION pi = {};
|
||||
|
||||
std::wstring mutableCommand = command;
|
||||
const DWORD flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE;
|
||||
|
||||
LOG_DEBUG("starting detached process as session user, command: %s", command.c_str());
|
||||
const BOOL ok = CreateProcessAsUserW(
|
||||
userToken, nullptr, mutableCommand.data(), nullptr, nullptr, FALSE, flags, environment, nullptr, &si, &pi
|
||||
);
|
||||
|
||||
DestroyEnvironmentBlock(environment);
|
||||
CloseHandle(userToken);
|
||||
|
||||
if (!ok) {
|
||||
LOG_ERR("could not start process as session user, error: %s", windowsErrorToString(GetLastError()).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MSWindowsProcess::createPipes()
|
||||
{
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ public:
|
|||
|
||||
static void shutdown(HANDLE handle, DWORD pid, int timeout = kDefaultShutdownTimeout);
|
||||
|
||||
/// Launch @p command as a detached process under the active console user's token, so the
|
||||
/// child does not inherit the caller's (SYSTEM) privileges.
|
||||
static bool startDetachedAsSessionUser(const std::wstring &command);
|
||||
|
||||
private:
|
||||
void setStartupInfo(STARTUPINFO &si);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if(WIN32)
|
||||
set(extra_libs version)
|
||||
set(extra_libs platform version)
|
||||
endif()
|
||||
|
||||
create_test(
|
||||
|
|
|
|||
Loading…
Reference in a new issue