Merge pull request #6762 from symless/issue-6567-zombie-processes
SYNERGY-92 Fixed deamon leaving zombie process hanging about feeding on memory
This commit is contained in:
commit
39902714ef
3 changed files with 65 additions and 15 deletions
|
|
@ -2,6 +2,7 @@ v1.12.x-snapshot
|
||||||
===========
|
===========
|
||||||
Bug fixes:
|
Bug fixes:
|
||||||
- #6753 Fixed a number of vulnerabilities detected by static analysis
|
- #6753 Fixed a number of vulnerabilities detected by static analysis
|
||||||
|
- #6567 Fixed Synergy spawning hundreds of zombie processes
|
||||||
- #6755 Fixed Vulnerability in vreadf function detected by Static analysis
|
- #6755 Fixed Vulnerability in vreadf function detected by Static analysis
|
||||||
- #6758 Account name with space on windows causes synergy to error when starting
|
- #6758 Account name with space on windows causes synergy to error when starting
|
||||||
- #6760 Synergy loses license when creating a System scope config
|
- #6760 Synergy loses license when creating a System scope config
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
#include <UserEnv.h>
|
#include <UserEnv.h>
|
||||||
#include <Shellapi.h>
|
#include <Shellapi.h>
|
||||||
|
|
||||||
|
#define CURRENT_PROCESS_ID 0
|
||||||
#define MAXIMUM_WAIT_TIME 3
|
#define MAXIMUM_WAIT_TIME 3
|
||||||
enum {
|
enum {
|
||||||
kOutputBufferSize = 4096
|
kOutputBufferSize = 4096
|
||||||
|
|
@ -338,6 +339,7 @@ MSWindowsWatchdog::startProcess()
|
||||||
// wait for program to fail.
|
// wait for program to fail.
|
||||||
ARCH->sleep(1);
|
ARCH->sleep(1);
|
||||||
if (!isProcessActive()) {
|
if (!isProcessActive()) {
|
||||||
|
closeProcessHandles(m_processInfo.dwProcessId);
|
||||||
throw XMSWindowsWatchdogError("process immediately stopped");
|
throw XMSWindowsWatchdogError("process immediately stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -376,9 +378,13 @@ MSWindowsWatchdog::startProcessInForeground(String& command)
|
||||||
si.dwFlags |= STARTF_USESHOWWINDOW;
|
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||||||
si.wShowWindow = SW_MINIMIZE;
|
si.wShowWindow = SW_MINIMIZE;
|
||||||
|
|
||||||
return CreateProcess(
|
BOOL result = CreateProcess(
|
||||||
NULL, LPSTR(command.c_str()), NULL, NULL,
|
NULL, LPSTR(command.c_str()), NULL, NULL,
|
||||||
TRUE, 0, NULL, NULL, &si, &m_processInfo);
|
TRUE, 0, NULL, NULL, &si, &m_processInfo);
|
||||||
|
|
||||||
|
m_children.insert(std::make_pair(m_processInfo.dwProcessId, m_processInfo));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
|
|
@ -409,6 +415,8 @@ MSWindowsWatchdog::startProcessAsUser(String& command, HANDLE userToken, LPSECUR
|
||||||
sa, NULL, TRUE, creationFlags,
|
sa, NULL, TRUE, creationFlags,
|
||||||
environment, NULL, &si, &m_processInfo);
|
environment, NULL, &si, &m_processInfo);
|
||||||
|
|
||||||
|
m_children.insert(std::make_pair(m_processInfo.dwProcessId, m_processInfo));
|
||||||
|
|
||||||
DestroyEnvironmentBlock(environment);
|
DestroyEnvironmentBlock(environment);
|
||||||
CloseHandle(userToken);
|
CloseHandle(userToken);
|
||||||
|
|
||||||
|
|
@ -529,13 +537,15 @@ MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout)
|
||||||
ARCH->sleep(1);
|
ARCH->sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeProcessHandles(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsWatchdog::shutdownExistingProcesses()
|
MSWindowsWatchdog::shutdownExistingProcesses()
|
||||||
{
|
{
|
||||||
// first we need to take a snapshot of the running processes
|
// first we need to take a snapshot of the running processes
|
||||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, CURRENT_PROCESS_ID);
|
||||||
if (snapshot == INVALID_HANDLE_VALUE) {
|
if (snapshot == INVALID_HANDLE_VALUE) {
|
||||||
LOG((CLOG_ERR "could not get process snapshot"));
|
LOG((CLOG_ERR "could not get process snapshot"));
|
||||||
throw XArch(new XArchEvalWindows);
|
throw XArch(new XArchEvalWindows);
|
||||||
|
|
@ -564,6 +574,7 @@ MSWindowsWatchdog::shutdownExistingProcesses()
|
||||||
|
|
||||||
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
|
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
|
||||||
shutdownProcess(handle, entry.th32ProcessID, 10);
|
shutdownProcess(handle, entry.th32ProcessID, 10);
|
||||||
|
CloseHandle(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,6 +592,7 @@ MSWindowsWatchdog::shutdownExistingProcesses()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearAllChildren();
|
||||||
CloseHandle(snapshot);
|
CloseHandle(snapshot);
|
||||||
m_processRunning = false;
|
m_processRunning = false;
|
||||||
}
|
}
|
||||||
|
|
@ -601,7 +613,7 @@ MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security)
|
||||||
m_elevateProcess = elevateProcess;
|
m_elevateProcess = elevateProcess;
|
||||||
|
|
||||||
BOOL createRet = startProcessAsUser(syntoolCommand, userToken, security);
|
BOOL createRet = startProcessAsUser(syntoolCommand, userToken, security);
|
||||||
|
auto pid = m_processInfo.dwProcessId;
|
||||||
if (!createRet) {
|
if (!createRet) {
|
||||||
DWORD rc = GetLastError();
|
DWORD rc = GetLastError();
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
|
|
@ -622,6 +634,7 @@ MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security)
|
||||||
}
|
}
|
||||||
m_ready = false;
|
m_ready = false;
|
||||||
ARCH->unlockMutex(m_mutex);
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
closeProcessHandles(pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -644,3 +657,22 @@ MSWindowsWatchdog::testOutput(String buffer)
|
||||||
ARCH->unlockMutex(m_mutex);
|
ARCH->unlockMutex(m_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MSWindowsWatchdog::closeProcessHandles(unsigned long pid, bool removeFromMap) {
|
||||||
|
auto processInfo = m_children.find(pid);
|
||||||
|
if (processInfo != m_children.end()) {
|
||||||
|
CloseHandle(processInfo->second.hProcess);
|
||||||
|
CloseHandle(processInfo->second.hThread);
|
||||||
|
if(removeFromMap) {
|
||||||
|
m_children.erase(processInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSWindowsWatchdog::clearAllChildren() {
|
||||||
|
for (auto it = m_children.begin(); it != m_children.end(); ++it)
|
||||||
|
{
|
||||||
|
closeProcessHandles(it->second.dwThreadId, false);
|
||||||
|
}
|
||||||
|
m_children.clear();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
class Thread;
|
class Thread;
|
||||||
class IpcLogOutputter;
|
class IpcLogOutputter;
|
||||||
|
|
@ -42,7 +43,7 @@ public:
|
||||||
virtual ~MSWindowsWatchdog();
|
virtual ~MSWindowsWatchdog();
|
||||||
|
|
||||||
void startAsync();
|
void startAsync();
|
||||||
std::string getCommand() const;
|
std::string getCommand() const;
|
||||||
void setCommand(const std::string& command, bool elevate);
|
void setCommand(const std::string& command, bool elevate);
|
||||||
void stop();
|
void stop();
|
||||||
bool isProcessActive();
|
bool isProcessActive();
|
||||||
|
|
@ -53,8 +54,8 @@ private:
|
||||||
void outputLoop(void*);
|
void outputLoop(void*);
|
||||||
void shutdownProcess(HANDLE handle, DWORD pid, int timeout);
|
void shutdownProcess(HANDLE handle, DWORD pid, int timeout);
|
||||||
void shutdownExistingProcesses();
|
void shutdownExistingProcesses();
|
||||||
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
|
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
|
||||||
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
|
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
|
||||||
void startProcess();
|
void startProcess();
|
||||||
BOOL startProcessAsUser(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
BOOL startProcessAsUser(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
||||||
BOOL startProcessInForeground(String& command);
|
BOOL startProcessInForeground(String& command);
|
||||||
|
|
@ -62,29 +63,45 @@ private:
|
||||||
void getActiveDesktop(LPSECURITY_ATTRIBUTES security);
|
void getActiveDesktop(LPSECURITY_ATTRIBUTES security);
|
||||||
void testOutput(String buffer);
|
void testOutput(String buffer);
|
||||||
void setStartupInfo(STARTUPINFO& si);
|
void setStartupInfo(STARTUPINFO& si);
|
||||||
|
void checkChildren();
|
||||||
|
/**
|
||||||
|
* @brief This closes the handles held to a child thread
|
||||||
|
* @param pid the ID of the process to kill, will do nothing if PID is not a valid child
|
||||||
|
* @param removeFromMap should the function remove the item from the children map
|
||||||
|
*/
|
||||||
|
void closeProcessHandles(unsigned long pid, bool removeFromMap = true);
|
||||||
|
/**
|
||||||
|
* @brief This kills off all children's handles created by this process
|
||||||
|
*/
|
||||||
|
void clearAllChildren();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* m_thread;
|
Thread* m_thread;
|
||||||
bool m_autoDetectCommand;
|
bool m_autoDetectCommand;
|
||||||
std::string m_command;
|
std::string m_command;
|
||||||
bool m_monitoring;
|
bool m_monitoring;
|
||||||
bool m_commandChanged;
|
bool m_commandChanged;
|
||||||
HANDLE m_stdOutWrite;
|
HANDLE m_stdOutWrite;
|
||||||
HANDLE m_stdOutRead;
|
HANDLE m_stdOutRead;
|
||||||
Thread* m_outputThread;
|
Thread* m_outputThread;
|
||||||
IpcServer& m_ipcServer;
|
IpcServer& m_ipcServer;
|
||||||
IpcLogOutputter& m_ipcLogOutputter;
|
IpcLogOutputter& m_ipcLogOutputter;
|
||||||
bool m_elevateProcess;
|
bool m_elevateProcess;
|
||||||
MSWindowsSession m_session;
|
MSWindowsSession m_session;
|
||||||
PROCESS_INFORMATION m_processInfo;
|
PROCESS_INFORMATION m_processInfo;
|
||||||
int m_processFailures;
|
int m_processFailures;
|
||||||
bool m_processRunning;
|
bool m_processRunning;
|
||||||
FileLogOutputter* m_fileLogOutputter;
|
FileLogOutputter* m_fileLogOutputter;
|
||||||
bool m_autoElevated;
|
bool m_autoElevated;
|
||||||
ArchMutex m_mutex;
|
ArchMutex m_mutex;
|
||||||
ArchCond m_condVar;
|
ArchCond m_condVar;
|
||||||
bool m_ready;
|
bool m_ready;
|
||||||
bool m_foreground;
|
bool m_foreground;
|
||||||
|
|
||||||
|
/// @brief Save the info of all process made
|
||||||
|
/// We will use this to track all processes we make and
|
||||||
|
/// kill off handels and children that we no longer need
|
||||||
|
std::map<unsigned long, PROCESS_INFORMATION> m_children;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Relauncher error
|
//! Relauncher error
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue