pull/744/merge
Oleg Nenashev 2023-02-28 14:05:35 +02:00 committed by GitHub
commit 42519c8220
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 52 deletions

View File

@ -5,7 +5,7 @@ using static WinSW.Native.HandleApis;
namespace WinSW.Native namespace WinSW.Native
{ {
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal readonly ref struct Handle internal readonly struct Handle : IDisposable
{ {
private readonly IntPtr handle; private readonly IntPtr handle;

View File

@ -34,12 +34,20 @@ namespace WinSW.Native
int processInformationLength, int processInformationLength,
IntPtr returnLength = default); IntPtr returnLength = default);
[DllImport(Libraries.Kernel32)]
internal static extern Handle OpenProcess(ProcessAccess desiredAccess, bool inheritHandle, int processId);
[DllImport(Libraries.Advapi32, SetLastError = true)] [DllImport(Libraries.Advapi32, SetLastError = true)]
internal static extern bool OpenProcessToken( internal static extern bool OpenProcessToken(
IntPtr processHandle, IntPtr processHandle,
TokenAccessLevels desiredAccess, TokenAccessLevels desiredAccess,
out Handle tokenHandle); out Handle tokenHandle);
internal enum ProcessAccess : uint
{
QueryInformation = 0x0400,
}
internal enum PROCESSINFOCLASS internal enum PROCESSINFOCLASS
{ {
ProcessBasicInformation = 0, ProcessBasicInformation = 0,

View File

@ -26,7 +26,11 @@ namespace WinSW.Util
{ {
foreach (var child in GetChildren(process)) foreach (var child in GetChildren(process))
{ {
StopProcessTree(child, stopTimeout, stopParentProcessFirst); using (child.Key)
using (child.Value)
{
StopProcessTree(child.Key, stopTimeout, stopParentProcessFirst);
}
} }
} }
@ -36,7 +40,11 @@ namespace WinSW.Util
{ {
foreach (var child in GetChildren(process)) foreach (var child in GetChildren(process))
{ {
StopProcessTree(child, stopTimeout, stopParentProcessFirst); using (child.Key)
using (child.Value)
{
StopProcessTree(child.Key, stopTimeout, stopParentProcessFirst);
}
} }
} }
} }
@ -95,47 +103,53 @@ namespace WinSW.Util
Logger.Debug($"Process {process.Id} has already exited."); Logger.Debug($"Process {process.Id} has already exited.");
} }
private static unsafe List<Process> GetChildren(Process process) // The handle is to keep a reference to the process.
private static unsafe List<KeyValuePair<Process, Handle>> GetChildren(Process process)
{ {
var startTime = process.StartTime; var startTime = process.StartTime;
int processId = process.Id; int processId = process.Id;
var children = new List<Process>(); var children = new List<KeyValuePair<Process, Handle>>();
foreach (var other in Process.GetProcesses()) foreach (var other in Process.GetProcesses())
{ {
var handle = OpenProcess(ProcessAccess.QueryInformation, false, other.Id);
if (handle == IntPtr.Zero)
{
goto Next;
}
try try
{ {
if (other.StartTime <= startTime) if (other.StartTime <= startTime)
{ {
goto Next; goto Next;
} }
var handle = other.Handle;
if (NtQueryInformationProcess(
handle,
PROCESSINFOCLASS.ProcessBasicInformation,
out var information,
sizeof(PROCESS_BASIC_INFORMATION)) != 0)
{
goto Next;
}
if ((int)information.InheritedFromUniqueProcessId == processId)
{
Logger.Debug($"Found child process {other.Id}.");
children.Add(other);
continue;
}
Next:
other.Dispose();
} }
catch (Exception e) when (e is InvalidOperationException || e is Win32Exception) catch (Exception e) when (e is InvalidOperationException || e is Win32Exception)
{ {
other.Dispose(); goto Next;
} }
if (NtQueryInformationProcess(
handle,
PROCESSINFOCLASS.ProcessBasicInformation,
out var information,
sizeof(PROCESS_BASIC_INFORMATION)) != 0)
{
goto Next;
}
if ((int)information.InheritedFromUniqueProcessId == processId)
{
Logger.Debug($"Found child process {other.Id}.");
children.Add(new(other, handle));
continue;
}
Next:
other.Dispose();
handle.Dispose();
} }
return children; return children;

View File

@ -10,6 +10,9 @@ namespace WinSW.Plugins
private const string Kernel32 = "kernel32.dll"; private const string Kernel32 = "kernel32.dll";
private const string NTDll = "ntdll.dll"; private const string NTDll = "ntdll.dll";
[DllImport(Kernel32)]
internal static extern bool CloseHandle(IntPtr objectHandle);
[DllImport(Kernel32)] [DllImport(Kernel32)]
internal static extern int IsWow64Process(IntPtr hProcess, out int Wow64Process); internal static extern int IsWow64Process(IntPtr hProcess, out int Wow64Process);
@ -53,6 +56,14 @@ namespace WinSW.Plugins
long BufferSize, long BufferSize,
long NumberOfBytesRead = default); long NumberOfBytesRead = default);
[DllImport(Kernel32)]
internal static extern IntPtr OpenProcess(ProcessAccess desiredAccess, bool inheritHandle, int processId);
internal enum ProcessAccess : uint
{
QueryInformation = 0x0400,
}
internal enum PROCESSINFOCLASS internal enum PROCESSINFOCLASS
{ {
ProcessBasicInformation = 0, ProcessBasicInformation = 0,

View File

@ -268,39 +268,54 @@ namespace WinSW.Plugins
// Ensure the process references the service // Ensure the process references the service
string expectedEnvVarName = WinSWSystem.EnvVarNameServiceId; string expectedEnvVarName = WinSWSystem.EnvVarNameServiceId;
string? affiliatedServiceId = ReadEnvironmentVariable(proc.Handle, expectedEnvVarName);
if (affiliatedServiceId is null && this.CheckWinSWEnvironmentVariable)
{
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
+ "The process has not been started by WinSW, hence it won't be terminated.");
var processHandle = OpenProcess(ProcessAccess.QueryInformation, false, pid);
if (processHandle == IntPtr.Zero)
{
Logger.Warn("Cannot get process handle of PID=" + pid + ". Assuming that the process has not been started by WinSW.");
return; return;
} }
// Check the service ID value try
if (this.CheckWinSWEnvironmentVariable && !this.ServiceId.Equals(affiliatedServiceId))
{ {
Logger.Warn("The process " + pid + " has been started by Windows service with ID='" + affiliatedServiceId + "'. " string? affiliatedServiceId = ReadEnvironmentVariable(processHandle, expectedEnvVarName);
+ "It is another service (current service id is '" + this.ServiceId + "'), hence the process won't be terminated."); if (affiliatedServiceId is null && this.CheckWinSWEnvironmentVariable)
return; {
} Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
+ "The process has not been started by WinSW, hence it won't be terminated.");
// Kill the runaway process return;
var bldr = new StringBuilder("Stopping the runaway process (pid="); }
bldr.Append(pid);
bldr.Append(") and its children. Environment was "); // Check the service ID value
if (!this.CheckWinSWEnvironmentVariable) if (this.CheckWinSWEnvironmentVariable && !this.ServiceId.Equals(affiliatedServiceId))
{
Logger.Warn("The process " + pid + " has been started by Windows service with ID='" + affiliatedServiceId + "'. "
+ "It is another service (current service id is '" + this.ServiceId + "'), hence the process won't be terminated.");
return;
}
// Kill the runaway process
var bldr = new StringBuilder("Stopping the runaway process (pid=");
bldr.Append(pid);
bldr.Append(") and its children. Environment was ");
if (!this.CheckWinSWEnvironmentVariable)
{
bldr.Append("not ");
}
bldr.Append("checked, affiliated service ID: ");
bldr.Append(affiliatedServiceId ?? "undefined");
bldr.Append(", process to kill: ");
bldr.Append(proc);
Logger.Warn(bldr.ToString());
ProcessHelper.StopProcessTree(proc, this.StopTimeout, this.StopParentProcessFirst);
}
finally
{ {
bldr.Append("not "); _ = CloseHandle(processHandle);
} }
bldr.Append("checked, affiliated service ID: ");
bldr.Append(affiliatedServiceId ?? "undefined");
bldr.Append(", process to kill: ");
bldr.Append(proc);
Logger.Warn(bldr.ToString());
ProcessHelper.StopProcessTree(proc, this.StopTimeout, this.StopParentProcessFirst);
} }
/// <summary> /// <summary>