Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Try harder to handle Ctrl+C #18

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 126 additions & 2 deletions winsup/cygwin/include/cygwin/exit_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,123 @@ inject_remote_thread_into_process(HANDLE process, LPTHREAD_START_ROUTINE address
return res;
}

#define PROCESS_BASIC_INFORMATION_SIZE_32 0x18
#define PEB_OFFSET_32 0x4
#define PARAMS_OFFSET_32 0x10
#define CONSOLE_FLAGS_OFFSET_32 0x14

#define PROCESS_BASIC_INFORMATION_SIZE_64 0x30
#define PEB_OFFSET_64 0x8
#define PARAMS_OFFSET_64 0x20
#define CONSOLE_FLAGS_OFFSET_64 0x18

/**
* Adjust the ConsoleFlags to allow the process to accept Ctrl+C.
*
* The handle must be opened with PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_WRITE.
*
* Returns 1 if the ConsoleFlags were cleared, 0 if they had already been cleared, and -1
* on unspecified error.
*/
static int
adjust_console_flag(HANDLE process)
{
union
{
char chars[PROCESS_BASIC_INFORMATION_SIZE_64];
ULONG32 ulong32;
ULONG64 ulong64;
} u;
int res = 0;
char flags;

#ifdef __LP64__
/* Are we looking at a 32-bit process from a 64-bit one? */
if (!NtQueryInformationProcess (process, ProcessWow64Information, &u.chars, 8, NULL) && u.ulong64)
{
SIZE_T size;
if (!ReadProcessMemory (process, (char *)u.ulong64 + PARAMS_OFFSET_32, u.chars, 4, &size) || size != 4)
return -1;
if (!ReadProcessMemory (process, (char *)(ULONG64)u.ulong32 + CONSOLE_FLAGS_OFFSET_32, &flags, 1, &size) || size != 1)
return -1;
if (flags == 1)
{
res = 1;
flags = 0;
if (!WriteProcessMemory (process, (char *)(ULONG64)u.ulong32 + CONSOLE_FLAGS_OFFSET_32, &flags, 1, &size) || size != 1)
return -1;
}
}

if (!NtQueryInformationProcess (process, ProcessBasicInformation, u.chars, PROCESS_BASIC_INFORMATION_SIZE_64, NULL))
{
SIZE_T size;
if (!ReadProcessMemory (process, (char *)*(ULONG64 *)(u.chars + PEB_OFFSET_64) + PARAMS_OFFSET_64, u.chars, 8, &size) || size != 8)
return -1;
if (!ReadProcessMemory (process, (char *)u.ulong64 + CONSOLE_FLAGS_OFFSET_64, &flags, 1, &size) || size != 1)
return -1;
if (flags == 1)
{
res = 1;
flags = 0;
if (!WriteProcessMemory (process, (char *)u.ulong64 + CONSOLE_FLAGS_OFFSET_64, &flags, 1, &size) || size != 1)
return -1;
}
}
#else
if (!NtQueryInformationProcess(process, ProcessBasicInformation, u.chars, PROCESS_BASIC_INFORMATION_SIZE_32, NULL) && (char *)*(ULONG32 *)(u.chars + PEB_OFFSET_32))
{
SIZE_T size;
if (!ReadProcessMemory (process, (char *)*(ULONG32 *)(u.chars + PEB_OFFSET_32) + PARAMS_OFFSET_32, u.chars, 8, &size) || size != 8)
return -1;
if (!ReadProcessMemory (process, (char *)u.ulong32 + CONSOLE_FLAGS_OFFSET_32, &flags, 1, &size) || size != 1)
return -1;
if (flags == 1)
{
res = 1;
flags = 0;
if (!WriteProcessMemory (process, (char *)u.ulong32 + CONSOLE_FLAGS_OFFSET_32, &flags, 1, &size) || size != 1)
return -1;
}
}

/* So maybe this is a 32-bit process looking at a 64-bit one? */
{
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
static NTSTATUS(NTAPI *NtWow64ReadVirtualMemory64)(HANDLE process, ULONG64 address, PVOID buffer, ULONG64 size, PULONG64 count);
static NTSTATUS(NTAPI *NtWow64WriteVirtualMemory64)(HANDLE process, ULONG64 address, PVOID buffer, ULONG64 size, PULONG64 count);
static NTSTATUS(NTAPI *NtWow64QueryInformationProcess64)(HANDLE process, PROCESSINFOCLASS info_class, PVOID buffer, ULONG size, PULONG count);
static int initialized;
ULONG64 size;

if (!initialized)
{
initialized = 1;
NtWow64ReadVirtualMemory64 = (typeof (NtWow64ReadVirtualMemory64))GetProcAddress (ntdll, "NtWow64ReadVirtualMemory64");
NtWow64WriteVirtualMemory64 = (typeof (NtWow64WriteVirtualMemory64))GetProcAddress (ntdll, "NtWow64WriteVirtualMemory64");
NtWow64QueryInformationProcess64 = (typeof (NtWow64QueryInformationProcess64))GetProcAddress (ntdll, "NtWow64QueryInformationProcess64");
}

if (NtWow64ReadVirtualMemory64 && NtWow64WriteVirtualMemory64 && NtWow64QueryInformationProcess64)
if (!NtWow64QueryInformationProcess64 (process, ProcessBasicInformation, u.chars, PROCESS_BASIC_INFORMATION_SIZE_64, NULL))
{
if (NtWow64ReadVirtualMemory64 (process, *(ULONG64 *)(u.chars + PEB_OFFSET_64) + PARAMS_OFFSET_64, u.chars, 8, &size) || size != 8)
return -1;
if (NtWow64ReadVirtualMemory64(process, u.ulong64 + CONSOLE_FLAGS_OFFSET_64, &flags, 1, &size) || size != 1)
return -1;
}
if (flags == 1)
{
res = 1;
flags = 0;
if (NtWow64WriteVirtualMemory64(process, u.ulong64 + CONSOLE_FLAGS_OFFSET_64, &flags, 1, &size) || size != 1)
return -1;
}
}
#endif
return res;
}

/**
* Terminates the process corresponding to the process ID
*
Expand All @@ -245,6 +362,7 @@ exit_one_process(HANDLE process, int exit_code)
LPTHREAD_START_ROUTINE address = NULL;
int signo = exit_code & 0x7f;

TODO: use IsProcessCritical() if available (Windows 8.1 and later) to skip this
switch (signo)
{
case SIGINT:
Expand All @@ -253,8 +371,14 @@ exit_one_process(HANDLE process, int exit_code)
if (address &&
!inject_remote_thread_into_process(process, address,
signo == SIGINT ?
CTRL_C_EVENT : CTRL_BREAK_EVENT))
return 0;
CTRL_C_EVENT :
CTRL_BREAK_EVENT)) {
DWORD code;
if (signo == SIGINT && !GetExitCodeProcess (process, &code) ||
code == STILL_ACTIVE && adjust_console_flag(process) > 0 &&
!inject_remote_thread_into_process(process, address, CTRL_C_EVENT))
return 0;
}
/* fall-through */
case SIGTERM:
address = get_exit_process_address_for_process(process);
Expand Down