From 7bebf7db8c2c7a147b24cf0c8e9cac2c7460093a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 1 Feb 2021 11:10:06 +0100 Subject: [PATCH] ntdll: Implement NtSetInformationDebugObject(). Signed-off-by: Alexandre Julliard --- dlls/kernel32/debugger.c | 16 +++++----- dlls/kernel32/tests/debugger.c | 23 ++++++++++++++ dlls/ntdll/ntdll.spec | 4 +-- dlls/ntdll/tests/info.c | 55 ++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/sync.c | 30 +++++++++++++++++++ include/wine/server_protocol.h | 16 +++++----- include/winternl.h | 7 +++++ server/debugger.c | 15 +++++----- server/protocol.def | 7 +++-- server/request.h | 9 +++--- server/trace.c | 9 +++--- 11 files changed, 154 insertions(+), 37 deletions(-) diff --git a/dlls/kernel32/debugger.c b/dlls/kernel32/debugger.c index b80b0f0afd1..6ccce02a8f3 100644 --- a/dlls/kernel32/debugger.c +++ b/dlls/kernel32/debugger.c @@ -23,8 +23,10 @@ #include "ntstatus.h" #define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" #include "winerror.h" -#include "wine/server.h" +#include "winternl.h" #include "kernel_private.h" #include "wine/asm.h" #include "wine/debug.h" @@ -165,13 +167,9 @@ BOOL WINAPI DebugBreakProcess(HANDLE process) */ BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill) { - BOOL ret = FALSE; + ULONG flag = kill ? DEBUG_KILL_ON_CLOSE : 0; - SERVER_START_REQ( set_debugger_kill_on_exit ) - { - req->kill_on_exit = kill; - ret = !wine_server_call_err( req ); - } - SERVER_END_REQ; - return ret; + return set_ntstatus( NtSetInformationDebugObject( DbgUiGetThreadDebugObject(), + DebugObjectKillProcessOnExitInformation, + &flag, sizeof(flag), NULL )); } diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index de7440d5ed8..b7ec9e99ed3 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -46,6 +46,7 @@ static void (WINAPI *pDbgBreakPoint)(void); static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process); static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process); static NTSTATUS (WINAPI *pNtCreateDebugObject)(HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG); +static NTSTATUS (WINAPI *pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,void *,ULONG,ULONG*); static NTSTATUS (WINAPI *pDbgUiConnectToDbg)(void); static HANDLE (WINAPI *pDbgUiGetThreadDebugObject)(void); static void (WINAPI *pDbgUiSetThreadDebugObject)(HANDLE); @@ -1735,6 +1736,7 @@ static void test_kill_on_exit(const char *argv0) HANDLE event, debug; DWORD exit_code; char *cmd; + ULONG val; event = CreateEventW(&sa, FALSE, FALSE, NULL); ok(event != NULL, "CreateEvent failed: %u\n", GetLastError()); @@ -1757,6 +1759,26 @@ static void test_kill_on_exit(const char *argv0) status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0xfffe ); ok( status == STATUS_INVALID_PARAMETER, "NtCreateDebugObject failed %x\n", status ); + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 ); + ok( !status, "NtCreateDebugObject failed %x\n", status ); + pDbgUiSetThreadDebugObject( debug ); + val = DEBUG_KILL_ON_CLOSE; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %x\n", status ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code); + + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE ); + ok( !status, "NtCreateDebugObject failed %x\n", status ); + pDbgUiSetThreadDebugObject( debug ); + val = 0; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %x\n", status ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == 0, "exit code = %08x\n", exit_code); + status = pDbgUiConnectToDbg(); ok( !status, "DbgUiConnectToDbg failed %x\n", status ); exit_code = run_child_wait( cmd, event ); @@ -1777,6 +1799,7 @@ START_TEST(debugger) pNtSuspendProcess = (void*)GetProcAddress(ntdll, "NtSuspendProcess"); pNtResumeProcess = (void*)GetProcAddress(ntdll, "NtResumeProcess"); pNtCreateDebugObject = (void*)GetProcAddress(ntdll, "NtCreateDebugObject"); + pNtSetInformationDebugObject = (void*)GetProcAddress(ntdll, "NtSetInformationDebugObject"); pDbgUiConnectToDbg = (void*)GetProcAddress(ntdll, "DbgUiConnectToDbg"); pDbgUiGetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiGetThreadDebugObject"); pDbgUiSetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiSetThreadDebugObject"); diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index e205927db63..bf7880372a5 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -373,7 +373,7 @@ @ stub NtSetHighEventPair @ stub NtSetHighWaitLowEventPair @ stub NtSetHighWaitLowThread -# @ stub NtSetInformationDebugObject +@ stdcall -syscall NtSetInformationDebugObject(long long ptr long ptr) @ stdcall -syscall NtSetInformationFile(long ptr ptr long long) @ stdcall -syscall NtSetInformationJobObject(long long ptr long) @ stdcall -syscall NtSetInformationKey(long long ptr long) @@ -1378,7 +1378,7 @@ @ stub ZwSetHighEventPair @ stub ZwSetHighWaitLowEventPair @ stub ZwSetHighWaitLowThread -# @ stub ZwSetInformationDebugObject +@ stdcall -private -syscall ZwSetInformationDebugObject(long long ptr long ptr) NtSetInformationDebugObject @ stdcall -private -syscall ZwSetInformationFile(long ptr ptr long long) NtSetInformationFile @ stdcall -private -syscall ZwSetInformationJobObject(long long ptr long) NtSetInformationJobObject @ stdcall -private -syscall ZwSetInformationKey(long long ptr long) NtSetInformationKey diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index de9ebb5879c..ec8f0ad6535 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -43,6 +43,8 @@ static BOOL (WINAPI * pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_R static DEP_SYSTEM_POLICY_TYPE (WINAPI * pGetSystemDEPPolicy)(void); static NTSTATUS (WINAPI * pNtOpenThread)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const CLIENT_ID *); static NTSTATUS (WINAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, void *, ULONG, ULONG *); +static NTSTATUS (WINAPI * pNtCreateDebugObject)( HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG ); +static NTSTATUS (WINAPI * pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,PVOID,ULONG,ULONG*); static BOOL is_wow64; @@ -92,6 +94,8 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtUnmapViewOfSection); NTDLL_GET_PROC(NtOpenThread); NTDLL_GET_PROC(NtQueryObject); + NTDLL_GET_PROC(NtCreateDebugObject); + NTDLL_GET_PROC(NtSetInformationDebugObject); /* not present before XP */ pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll, "NtGetCurrentProcessorNumber"); @@ -2749,6 +2753,56 @@ static void test_wow64(void) ok( !NtCurrentTeb()->WowTebOffset, "WowTebOffset set to %x\n", NtCurrentTeb()->WowTebOffset ); } +static void test_debug_object(void) +{ + NTSTATUS status; + HANDLE handle; + OBJECT_ATTRIBUTES attr = { sizeof(attr) }; + ULONG len, flag = 0; + + status = pNtCreateDebugObject( &handle, DEBUG_ALL_ACCESS, &attr, 0 ); + ok( !status, "NtCreateDebugObject failed %x\n", status ); + status = pNtSetInformationDebugObject( handle, 0, &flag, sizeof(ULONG), &len ); + ok( status == STATUS_INVALID_PARAMETER, "NtSetInformationDebugObject failed %x\n", status ); + status = pNtSetInformationDebugObject( handle, 2, &flag, sizeof(ULONG), &len ); + ok( status == STATUS_INVALID_PARAMETER, "NtSetInformationDebugObject failed %x\n", status ); + status = pNtSetInformationDebugObject( (HANDLE)0xdead, DebugObjectKillProcessOnExitInformation, + &flag, sizeof(ULONG), &len ); + ok( status == STATUS_INVALID_HANDLE, "NtSetInformationDebugObject failed %x\n", status ); + + len = 0xdead; + status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation, + &flag, sizeof(ULONG) + 1, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtSetInformationDebugObject failed %x\n", status ); + ok( len == sizeof(ULONG), "wrong len %u\n", len ); + + len = 0xdead; + status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation, + &flag, sizeof(ULONG) - 1, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtSetInformationDebugObject failed %x\n", status ); + ok( len == sizeof(ULONG), "wrong len %u\n", len ); + + len = 0xdead; + status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation, + &flag, sizeof(ULONG), &len ); + ok( !status, "NtSetInformationDebugObject failed %x\n", status ); + ok( !len, "wrong len %u\n", len ); + + flag = DEBUG_KILL_ON_CLOSE; + status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation, + &flag, sizeof(ULONG), &len ); + ok( !status, "NtSetInformationDebugObject failed %x\n", status ); + ok( !len, "wrong len %u\n", len ); + + for (flag = 2; flag; flag <<= 1) + { + status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation, + &flag, sizeof(ULONG), &len ); + ok( status == STATUS_INVALID_PARAMETER, "NtSetInformationDebugObject failed %x\n", status ); + } + + pNtClose( handle ); +} START_TEST(info) { @@ -2808,6 +2862,7 @@ START_TEST(info) test_affinity(); test_wow64(); + test_debug_object(); /* belongs to its own file */ test_readvirtualmemory(); diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 7311b34d6e5..5132daf9e0e 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -934,6 +934,36 @@ NTSTATUS WINAPI NtCreateDebugObject( HANDLE *handle, ACCESS_MASK access, } +/********************************************************************** + * NtSetInformationDebugObject (NTDLL.@) + */ +NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS class, + void *info, ULONG len, ULONG *ret_len ) +{ + NTSTATUS ret; + ULONG flags; + + if (class != DebugObjectKillProcessOnExitInformation) return STATUS_INVALID_PARAMETER; + if (len != sizeof(ULONG)) + { + if (ret_len) *ret_len = sizeof(ULONG); + return STATUS_INFO_LENGTH_MISMATCH; + } + flags = *(ULONG *)info; + if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ( set_debug_obj_info ) + { + req->debug = wine_server_obj_handle( handle ); + req->flags = flags; + ret = wine_server_call( req ); + } + SERVER_END_REQ; + if (!ret && ret_len) *ret_len = 0; + return ret; +} + + /************************************************************************** * NtCreateDirectoryObject (NTDLL.@) */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 04a74d20b71..eff048111f9 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2105,12 +2105,14 @@ struct debug_process_reply -struct set_debugger_kill_on_exit_request +struct set_debug_obj_info_request { struct request_header __header; - int kill_on_exit; + obj_handle_t debug; + unsigned int flags; + char __pad_20[4]; }; -struct set_debugger_kill_on_exit_reply +struct set_debug_obj_info_reply { struct reply_header __header; }; @@ -5447,7 +5449,7 @@ enum request REQ_get_exception_status, REQ_continue_debug_event, REQ_debug_process, - REQ_set_debugger_kill_on_exit, + REQ_set_debug_obj_info, REQ_read_process_memory, REQ_write_process_memory, REQ_create_key, @@ -5729,7 +5731,7 @@ union generic_request struct get_exception_status_request get_exception_status_request; struct continue_debug_event_request continue_debug_event_request; struct debug_process_request debug_process_request; - struct set_debugger_kill_on_exit_request set_debugger_kill_on_exit_request; + struct set_debug_obj_info_request set_debug_obj_info_request; struct read_process_memory_request read_process_memory_request; struct write_process_memory_request write_process_memory_request; struct create_key_request create_key_request; @@ -6009,7 +6011,7 @@ union generic_reply struct get_exception_status_reply get_exception_status_reply; struct continue_debug_event_reply continue_debug_event_reply; struct debug_process_reply debug_process_reply; - struct set_debugger_kill_on_exit_reply set_debugger_kill_on_exit_reply; + struct set_debug_obj_info_reply set_debug_obj_info_reply; struct read_process_memory_reply read_process_memory_reply; struct write_process_memory_reply write_process_memory_reply; struct create_key_reply create_key_reply; @@ -6211,7 +6213,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 659 +#define SERVER_PROTOCOL_VERSION 660 /* ### protocol_version end ### */ diff --git a/include/winternl.h b/include/winternl.h index 3afb6b434c0..ac2dece8252 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3015,6 +3015,12 @@ typedef struct _PS_CREATE_INFO #define DEBUG_KILL_ON_CLOSE 0x1 +typedef enum _DEBUGOBJECTINFOCLASS +{ + DebugObjectKillProcessOnExitInformation = 1, + MaxDebugObjectInfoClass +} DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS; + /*********************************************************************** * Function declarations */ @@ -3256,6 +3262,7 @@ NTSYSAPI NTSTATUS WINAPI NtSetEvent(HANDLE,LONG*); NTSYSAPI NTSTATUS WINAPI NtSetHighEventPair(HANDLE); NTSYSAPI NTSTATUS WINAPI NtSetHighWaitLowEventPair(HANDLE); NTSYSAPI NTSTATUS WINAPI NtSetHighWaitLowThread(VOID); +NTSYSAPI NTSTATUS WINAPI NtSetInformationDebugObject(HANDLE,DEBUGOBJECTINFOCLASS,PVOID,ULONG,ULONG*); NTSYSAPI NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS); NTSYSAPI NTSTATUS WINAPI NtSetInformationJobObject(HANDLE,JOBOBJECTINFOCLASS,PVOID,ULONG); NTSYSAPI NTSTATUS WINAPI NtSetInformationKey(HANDLE,const int,PVOID,ULONG); diff --git a/server/debugger.c b/server/debugger.c index 252a0a62b4b..e466be2623b 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -747,13 +747,12 @@ DECL_HANDLER(get_exception_status) } } -/* set debugger kill on exit flag */ -DECL_HANDLER(set_debugger_kill_on_exit) +/* set debug object information */ +DECL_HANDLER(set_debug_obj_info) { - if (!current->debug_obj) - { - set_error( STATUS_ACCESS_DENIED ); - return; - } - current->debug_obj->flags = req->kill_on_exit ? DEBUG_KILL_ON_CLOSE : 0; + struct debug_obj *debug_obj; + + if (!(debug_obj = get_debug_obj( current->process, req->debug, DEBUG_SET_INFORMATION ))) return; + debug_obj->flags = req->flags; + release_object( debug_obj ); } diff --git a/server/protocol.def b/server/protocol.def index 8124452fe0e..e846aa9bf05 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1645,9 +1645,10 @@ struct process_info @END -/* Set debugger kill on exit flag */ -@REQ(set_debugger_kill_on_exit) - int kill_on_exit; /* 0=detach/1=kill debuggee when debugger dies */ +/* Set debug object information */ +@REQ(set_debug_obj_info) + obj_handle_t debug; /* debug object */ + unsigned int flags; /* object flags */ @END diff --git a/server/request.h b/server/request.h index 42891c2cf3e..78dcf8b7973 100644 --- a/server/request.h +++ b/server/request.h @@ -196,7 +196,7 @@ DECL_HANDLER(queue_exception_event); DECL_HANDLER(get_exception_status); DECL_HANDLER(continue_debug_event); DECL_HANDLER(debug_process); -DECL_HANDLER(set_debugger_kill_on_exit); +DECL_HANDLER(set_debug_obj_info); DECL_HANDLER(read_process_memory); DECL_HANDLER(write_process_memory); DECL_HANDLER(create_key); @@ -477,7 +477,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_exception_status, (req_handler)req_continue_debug_event, (req_handler)req_debug_process, - (req_handler)req_set_debugger_kill_on_exit, + (req_handler)req_set_debug_obj_info, (req_handler)req_read_process_memory, (req_handler)req_write_process_memory, (req_handler)req_create_key, @@ -1163,8 +1163,9 @@ C_ASSERT( FIELD_OFFSET(struct debug_process_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct debug_process_request, debug) == 16 ); C_ASSERT( FIELD_OFFSET(struct debug_process_request, attach) == 20 ); C_ASSERT( sizeof(struct debug_process_request) == 24 ); -C_ASSERT( FIELD_OFFSET(struct set_debugger_kill_on_exit_request, kill_on_exit) == 12 ); -C_ASSERT( sizeof(struct set_debugger_kill_on_exit_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct set_debug_obj_info_request, debug) == 12 ); +C_ASSERT( FIELD_OFFSET(struct set_debug_obj_info_request, flags) == 16 ); +C_ASSERT( sizeof(struct set_debug_obj_info_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, addr) == 16 ); C_ASSERT( sizeof(struct read_process_memory_request) == 24 ); diff --git a/server/trace.c b/server/trace.c index f817496470d..7ec0f2c9907 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2211,9 +2211,10 @@ static void dump_debug_process_request( const struct debug_process_request *req fprintf( stderr, ", attach=%d", req->attach ); } -static void dump_set_debugger_kill_on_exit_request( const struct set_debugger_kill_on_exit_request *req ) +static void dump_set_debug_obj_info_request( const struct set_debug_obj_info_request *req ) { - fprintf( stderr, " kill_on_exit=%d", req->kill_on_exit ); + fprintf( stderr, " debug=%04x", req->debug ); + fprintf( stderr, ", flags=%08x", req->flags ); } static void dump_read_process_memory_request( const struct read_process_memory_request *req ) @@ -4475,7 +4476,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_exception_status_request, (dump_func)dump_continue_debug_event_request, (dump_func)dump_debug_process_request, - (dump_func)dump_set_debugger_kill_on_exit_request, + (dump_func)dump_set_debug_obj_info_request, (dump_func)dump_read_process_memory_request, (dump_func)dump_write_process_memory_request, (dump_func)dump_create_key_request, @@ -5031,7 +5032,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_exception_status", "continue_debug_event", "debug_process", - "set_debugger_kill_on_exit", + "set_debug_obj_info", "read_process_memory", "write_process_memory", "create_key",