[PATCH] server: Allow skipping debug handle retrieval in get_process_debug_info.

Jinoh Kang jinoh.kang.kr at gmail.com
Sat Dec 4 10:05:36 CST 2021


Today, Wine uses NtQueryInformationProcess/ProcessDebugPort to detect
whether the current process is being debugged.  If it is, the process
issues a breakpoint to yield control to the debugger.

Some debuggers (e.g. latest CDB) appear to create debug handles with
restricted DACL, which causes querying debug port to fail with
STATUS_ACCESS_DENIED.  This results in the debuggee erroneously
skipping the initial breakpoint.

Fix this by making retrieval of debug port object handle optional.
Also, skip debug port object handle retrieval if serving requests that
don't need it (i.e. ProcessDebugPort and ProcessDebugFlags).

This also eliminates the extra round trip to the server for closing the
unneeded debug port object handle.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
 dlls/ntdll/unix/process.c      | 13 ++++---------
 include/wine/server_protocol.h |  4 +++-
 server/process.c               |  2 +-
 server/protocol.def            |  1 +
 server/request.h               |  3 ++-
 server/trace.c                 |  1 +
 6 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c
index c834ef85c79..dfe040eeb25 100644
--- a/dlls/ntdll/unix/process.c
+++ b/dlls/ntdll/unix/process.c
@@ -1259,19 +1259,16 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
             if (!info) ret = STATUS_ACCESS_VIOLATION;
             else
             {
-                HANDLE debug;
-
                 SERVER_START_REQ(get_process_debug_info)
                 {
                     req->handle = wine_server_obj_handle( handle );
+                    req->want_debug_obj = 0;
                     ret = wine_server_call( req );
-                    debug = wine_server_ptr_handle( reply->debug );
                 }
                 SERVER_END_REQ;
                 if (ret == STATUS_SUCCESS)
                 {
                     *(DWORD_PTR *)info = ~0ul;
-                    NtClose( debug );
                 }
                 else if (ret == STATUS_PORT_NOT_SET)
                 {
@@ -1290,18 +1287,15 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
             if (!info) ret = STATUS_ACCESS_VIOLATION;
             else
             {
-                HANDLE debug;
-
                 SERVER_START_REQ(get_process_debug_info)
                 {
                     req->handle = wine_server_obj_handle( handle );
+                    req->want_debug_obj = 0;
                     ret = wine_server_call( req );
-                    debug = wine_server_ptr_handle( reply->debug );
                     *(DWORD *)info = reply->debug_children;
                 }
                 SERVER_END_REQ;
-                if (ret == STATUS_SUCCESS) NtClose( debug );
-                else if (ret == STATUS_PORT_NOT_SET) ret = STATUS_SUCCESS;
+                if (ret == STATUS_PORT_NOT_SET) ret = STATUS_SUCCESS;
             }
         }
         else ret = STATUS_INFO_LENGTH_MISMATCH;
@@ -1323,6 +1317,7 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
                 SERVER_START_REQ(get_process_debug_info)
                 {
                     req->handle = wine_server_obj_handle( handle );
+                    req->want_debug_obj = 1;
                     ret = wine_server_call( req );
                     *(HANDLE *)info = wine_server_ptr_handle( reply->debug );
                 }
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index b37a8e8e056..eb880b98f46 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1018,6 +1018,8 @@ struct get_process_debug_info_request
 {
     struct request_header __header;
     obj_handle_t handle;
+    int          want_debug_obj;
+    char __pad_20[4];
 };
 struct get_process_debug_info_reply
 {
@@ -6279,7 +6281,7 @@ union generic_reply
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 737
+#define SERVER_PROTOCOL_VERSION 738
 
 /* ### protocol_version end ### */
 
diff --git a/server/process.c b/server/process.c
index 6d794ba5ead..635ab9b6450 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1528,7 +1528,7 @@ DECL_HANDLER(get_process_debug_info)
 
     reply->debug_children = process->debug_children;
     if (!process->debug_obj) set_error( STATUS_PORT_NOT_SET );
-    else reply->debug = alloc_handle( current->process, process->debug_obj, DEBUG_ALL_ACCESS, 0 );
+    else if (req->want_debug_obj) reply->debug = alloc_handle( current->process, process->debug_obj, DEBUG_ALL_ACCESS, 0 );
     release_object( process );
 }
 
diff --git a/server/protocol.def b/server/protocol.def
index c83e6a2ef7c..1e73e2783f8 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -968,6 +968,7 @@ typedef struct
 /* Retrieve debug information about a process */
 @REQ(get_process_debug_info)
     obj_handle_t handle;           /* process handle */
+    int          want_debug_obj;   /* want debug port object? */
 @REPLY
     obj_handle_t debug;            /* handle to debug port */
     int          debug_children;   /* inherit debugger to child processes */
diff --git a/server/request.h b/server/request.h
index 6a63e842357..95473ae762f 100644
--- a/server/request.h
+++ b/server/request.h
@@ -789,7 +789,8 @@ C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, priority) == 56 );
 C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, machine) == 60 );
 C_ASSERT( sizeof(struct get_process_info_reply) == 64 );
 C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_request, handle) == 12 );
-C_ASSERT( sizeof(struct get_process_debug_info_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_request, want_debug_obj) == 16 );
+C_ASSERT( sizeof(struct get_process_debug_info_request) == 24 );
 C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_reply, debug) == 8 );
 C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_reply, debug_children) == 12 );
 C_ASSERT( sizeof(struct get_process_debug_info_reply) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 99c5d3996ab..d708c361602 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1585,6 +1585,7 @@ static void dump_get_process_info_reply( const struct get_process_info_reply *re
 static void dump_get_process_debug_info_request( const struct get_process_debug_info_request *req )
 {
     fprintf( stderr, " handle=%04x", req->handle );
+    fprintf( stderr, ", want_debug_obj=%d", req->want_debug_obj );
 }
 
 static void dump_get_process_debug_info_reply( const struct get_process_debug_info_reply *req )
-- 
2.31.1




More information about the wine-devel mailing list