[PATCH 2/3] ntdll: Implement ProcessHandleInformation info class.

Nikolay Sivov nsivov at codeweavers.com
Mon May 23 09:09:52 CDT 2022


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ntdll/tests/info.c        | 33 +++++++++++++++++++++++
 dlls/ntdll/unix/process.c      | 49 ++++++++++++++++++++++++++++++++++
 dlls/wow64/process.c           | 40 +++++++++++++++++++++++++++
 dlls/wow64/struct32.h          | 18 +++++++++++++
 include/wine/server_protocol.h | 20 +++++++++++++-
 include/winternl.h             | 18 +++++++++++++
 server/handle.c                | 31 +++++++++++++++++++++
 server/protocol.def            |  9 +++++++
 server/request.h               |  6 +++++
 server/trace.c                 | 14 ++++++++++
 10 files changed, 237 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 89503093b17..dc141c6bf9c 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -2559,6 +2559,38 @@ static void test_query_process_debug_flags(int argc, char **argv)
     }
 }
 
+static void test_query_process_handles(void)
+{
+    PROCESS_HANDLE_SNAPSHOT_INFORMATION *snapshot;
+    ULONG ret_length, length;
+    NTSTATUS status;
+    unsigned int i;
+
+    ret_length = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, NULL, 0, &ret_length);
+    ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#lx.\n", status);
+
+    length = FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[1]);
+    snapshot = malloc(length);
+    ret_length = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, snapshot, length, &ret_length);
+    ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#lx.\n", status);
+    ok(ret_length, "Unexpected length %lu.\n", ret_length);
+    free(snapshot);
+
+    snapshot = malloc(ret_length);
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessHandleInformation, snapshot, ret_length, &ret_length);
+    ok(status == STATUS_SUCCESS, "Unexpected status %#lx.\n", status);
+    ok(ret_length, "Unexpected return length.\n");
+    ok(snapshot->NumberOfHandles, "Unexpected handle count.\n");
+    for (i = 0; i < min(3, snapshot->NumberOfHandles); ++i)
+    {
+        PROCESS_HANDLE_TABLE_ENTRY_INFO *ptr = &snapshot->Handles[i];
+        ok(!!ptr->HandleValue, "Unexpected handle.\n");
+    }
+    free(snapshot);
+}
+
 static void test_readvirtualmemory(void)
 {
     HANDLE process;
@@ -3588,6 +3620,7 @@ START_TEST(info)
     test_query_process_debug_object_handle(argc, argv);
     test_query_process_debug_flags(argc, argv);
     test_query_process_image_info();
+    test_query_process_handles();
     test_mapprotection();
     test_threadstack();
 
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c
index 078ad75099d..649a26be8e4 100644
--- a/dlls/ntdll/unix/process.c
+++ b/dlls/ntdll/unix/process.c
@@ -1094,6 +1094,13 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
     UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled);
     UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination);
     UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing);
+    UNIMPLEMENTED_INFO_CLASS(ProcessImageFileMapping);
+    UNIMPLEMENTED_INFO_CLASS(ProcessAffinityUpdateMode);
+    UNIMPLEMENTED_INFO_CLASS(ProcessMemoryAllocationMode);
+    UNIMPLEMENTED_INFO_CLASS(ProcessGroupInformation);
+    UNIMPLEMENTED_INFO_CLASS(ProcessTokenVirtualizationEnabled);
+    UNIMPLEMENTED_INFO_CLASS(ProcessConsoleHostProcess);
+    UNIMPLEMENTED_INFO_CLASS(ProcessWindowInformation);
 
     case ProcessBasicInformation:
         {
@@ -1496,6 +1503,48 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
         else ret = STATUS_INFO_LENGTH_MISMATCH;
         break;
 
+    case ProcessHandleInformation:
+        if (size >= sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION))
+        {
+            struct handle_info *handle_info;
+            unsigned int i, num_handles;
+
+            num_handles = (size - FIELD_OFFSET( PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles )) / sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO);
+            if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
+
+            SERVER_START_REQ(get_process_handle_info)
+            {
+                req->handle = wine_server_obj_handle( handle );
+                wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
+                if (!(ret = wine_server_call( req )))
+                {
+                    PROCESS_HANDLE_SNAPSHOT_INFORMATION *snapshot = info;
+                    snapshot->NumberOfHandles = reply->handle_count;
+                    snapshot->Reserved = 0;
+                    for (i = 0; i < snapshot->NumberOfHandles; i++)
+                    {
+                        PROCESS_HANDLE_TABLE_ENTRY_INFO *entry = &snapshot->Handles[i];
+                        memset( entry, 0, sizeof(*entry) );
+                        entry->HandleValue      = handle_info[i].handle;
+                        entry->GrantedAccess    = handle_info[i].access;
+                        entry->HandleAttributes = handle_info[i].attributes;
+                        /* FIXME: Fill out remaining fields */
+                    }
+                    len = FIELD_OFFSET( PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[reply->handle_count] );
+                }
+                else if (ret == STATUS_BUFFER_TOO_SMALL)
+                {
+                    len = FIELD_OFFSET( PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[reply->handle_count] );
+                    ret = STATUS_INFO_LENGTH_MISMATCH;
+                }
+            }
+            SERVER_END_REQ;
+
+            free(handle_info);
+        }
+        else ret = STATUS_INFO_LENGTH_MISMATCH;
+        break;
+
     default:
         FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
               handle, class, info, size, ret_len );
diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c
index 82ca4181116..a62d6073752 100644
--- a/dlls/wow64/process.c
+++ b/dlls/wow64/process.c
@@ -847,6 +847,46 @@ NTSTATUS WINAPI wow64_NtQueryInformationProcess( UINT *args )
         if (retlen) *retlen = sizeof(SECTION_IMAGE_INFORMATION32);
         return STATUS_INFO_LENGTH_MISMATCH;
 
+    case ProcessHandleInformation:
+        if (len >= sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION32))
+        {
+            PROCESS_HANDLE_SNAPSHOT_INFORMATION *info = NULL;
+            PROCESS_HANDLE_SNAPSHOT_INFORMATION32 *info32 = ptr;
+            ULONG size = 0, retsize = 0, count, i;
+
+            if (ptr)
+            {
+                size = info32->NumberOfHandles * FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles[info->NumberOfHandles]);
+                info = Wow64AllocateTemp( size );
+            }
+
+            if (!(status = NtQueryInformationProcess( handle, class, info, size, &retsize )))
+            {
+                info32->NumberOfHandles = info->NumberOfHandles;
+                for (i = 0; i < info->NumberOfHandles; ++i)
+                {
+                    PROCESS_HANDLE_TABLE_ENTRY_INFO32 *entry32 = &info32->Handles[i];
+                    const PROCESS_HANDLE_TABLE_ENTRY_INFO *entry = &info->Handles[i];
+
+                    entry32->HandleValue      = entry->HandleValue;
+                    entry32->HandleCount      = entry->HandleCount;
+                    entry32->PointerCount     = entry->PointerCount;
+                    entry32->GrantedAccess    = entry->GrantedAccess;
+                    entry32->ObjectTypeIndex  = entry->ObjectTypeIndex;
+                    entry32->HandleAttributes = entry->HandleAttributes;
+                }
+                if (retlen) *retlen = FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION32, Handles[info->NumberOfHandles]);
+            }
+            else if (status == STATUS_INFO_LENGTH_MISMATCH)
+            {
+                count = (retsize - FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION, Handles)) / sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO);
+                if (retlen) *retlen = FIELD_OFFSET(PROCESS_HANDLE_SNAPSHOT_INFORMATION32, Handles[count]);
+            }
+            return status;
+        }
+        if (retlen) *retlen = sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION32);
+        return STATUS_INFO_LENGTH_MISMATCH;
+
     default:
         FIXME( "unsupported class %u\n", class );
         return STATUS_INVALID_INFO_CLASS;
diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h
index b096c8d587b..466ff38582d 100644
--- a/dlls/wow64/struct32.h
+++ b/dlls/wow64/struct32.h
@@ -650,6 +650,24 @@ typedef struct
     ULONG                       Reserved4;
 } SYSTEM_EXTENDED_THREAD_INFORMATION32;
 
+typedef struct
+{
+    ULONG HandleValue;
+    ULONG HandleCount;
+    ULONG PointerCount;
+    ULONG GrantedAccess;
+    ULONG ObjectTypeIndex;
+    ULONG HandleAttributes;
+    ULONG Reserved;
+} PROCESS_HANDLE_TABLE_ENTRY_INFO32;
+
+typedef struct
+{
+    ULONG NumberOfHandles;
+    ULONG Reserved;
+    PROCESS_HANDLE_TABLE_ENTRY_INFO32 Handles[1];
+} PROCESS_HANDLE_SNAPSHOT_INFORMATION32;
+
 struct __server_iovec32
 {
     ULONG        ptr;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 868add58abf..fed5ecb8aad 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -5445,6 +5445,21 @@ struct get_next_thread_reply
 };
 
 
+
+struct get_process_handle_info_request
+{
+    struct request_header __header;
+    obj_handle_t handle;
+};
+struct get_process_handle_info_reply
+{
+    struct reply_header __header;
+    unsigned int handle_count;
+    /* VARARG(data,handle_infos); */
+    char __pad_12[4];
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -5722,6 +5737,7 @@ enum request
     REQ_suspend_process,
     REQ_resume_process,
     REQ_get_next_thread,
+    REQ_get_process_handle_info,
     REQ_NB_REQUESTS
 };
 
@@ -6004,6 +6020,7 @@ union generic_request
     struct suspend_process_request suspend_process_request;
     struct resume_process_request resume_process_request;
     struct get_next_thread_request get_next_thread_request;
+    struct get_process_handle_info_request get_process_handle_info_request;
 };
 union generic_reply
 {
@@ -6284,11 +6301,12 @@ union generic_reply
     struct suspend_process_reply suspend_process_reply;
     struct resume_process_reply resume_process_reply;
     struct get_next_thread_reply get_next_thread_reply;
+    struct get_process_handle_info_reply get_process_handle_info_reply;
 };
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 751
+#define SERVER_PROTOCOL_VERSION 752
 
 /* ### protocol_version end ### */
 
diff --git a/include/winternl.h b/include/winternl.h
index c992eaebf11..62874b3ebbe 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2244,6 +2244,24 @@ typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION_EX
     PROCESS_STACK_ALLOCATION_INFORMATION AllocInfo;
 } PROCESS_STACK_ALLOCATION_INFORMATION_EX, *PPROCESS_STACK_ALLOCATION_INFORMATION_EX;
 
+typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO
+{
+    ULONG_PTR HandleValue;
+    ULONG_PTR HandleCount;
+    ULONG_PTR PointerCount;
+    ULONG GrantedAccess;
+    ULONG ObjectTypeIndex;
+    ULONG HandleAttributes;
+    ULONG Reserved;
+} PROCESS_HANDLE_TABLE_ENTRY_INFO;
+
+typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION
+{
+    ULONG_PTR NumberOfHandles;
+    ULONG_PTR Reserved;
+    PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];
+} PROCESS_HANDLE_SNAPSHOT_INFORMATION;
+
 typedef struct _RTL_HEAP_DEFINITION {
     ULONG Length; /* = sizeof(RTL_HEAP_DEFINITION) */
 
diff --git a/server/handle.c b/server/handle.c
index 38ad80da267..89de2741f37 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -866,6 +866,37 @@ DECL_HANDLER(get_system_handles)
     }
 }
 
+/* Get a process handle snapshot */
+DECL_HANDLER(get_process_handle_info)
+{
+    struct enum_handle_info info;
+    struct handle_info *handle;
+    struct process *process;
+    data_size_t max_handles;
+
+    max_handles = get_reply_max_size() / sizeof(*handle);
+    if (!(process = get_process_from_handle( req->handle, max_handles ? PROCESS_DUP_HANDLE : PROCESS_QUERY_INFORMATION )))
+        return;
+
+    info.handle = NULL;
+    info.count  = 0;
+    enum_handles( process, &info );
+    reply->handle_count = info.count;
+
+    if (max_handles)
+    {
+        if (max_handles < info.count)
+            set_error( STATUS_BUFFER_TOO_SMALL );
+        else if ((handle = set_reply_data_size( info.count * sizeof(*handle) )))
+        {
+            info.handle = handle;
+            enum_handles( process, &info );
+        }
+    }
+
+    release_object( process );
+}
+
 DECL_HANDLER(make_temporary)
 {
     struct object *obj;
diff --git a/server/protocol.def b/server/protocol.def
index 2be1658fca2..b4050c52b02 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3747,3 +3747,12 @@ struct handle_info
 @REPLY
     obj_handle_t handle;       /* next thread handle */
 @END
+
+
+/* Get a process handles snapshot */
+ at REQ(get_process_handle_info)
+    obj_handle_t handle;       /* process handle */
+ at REPLY
+    unsigned int handle_count; /* count of process handles */
+    VARARG(data,handle_infos); /* handle information */
+ at END
diff --git a/server/request.h b/server/request.h
index 7fd63905e0e..ca2c835b232 100644
--- a/server/request.h
+++ b/server/request.h
@@ -394,6 +394,7 @@ DECL_HANDLER(terminate_job);
 DECL_HANDLER(suspend_process);
 DECL_HANDLER(resume_process);
 DECL_HANDLER(get_next_thread);
+DECL_HANDLER(get_process_handle_info);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -675,6 +676,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_suspend_process,
     (req_handler)req_resume_process,
     (req_handler)req_get_next_thread,
+    (req_handler)req_get_process_handle_info,
 };
 
 C_ASSERT( sizeof(abstime_t) == 8 );
@@ -2255,6 +2257,10 @@ C_ASSERT( FIELD_OFFSET(struct get_next_thread_request, flags) == 28 );
 C_ASSERT( sizeof(struct get_next_thread_request) == 32 );
 C_ASSERT( FIELD_OFFSET(struct get_next_thread_reply, handle) == 8 );
 C_ASSERT( sizeof(struct get_next_thread_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_process_handle_info_request, handle) == 12 );
+C_ASSERT( sizeof(struct get_process_handle_info_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_process_handle_info_reply, handle_count) == 8 );
+C_ASSERT( sizeof(struct get_process_handle_info_reply) == 16 );
 
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 15ca4e7d71e..4c9a6e9de22 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -4486,6 +4486,17 @@ static void dump_get_next_thread_reply( const struct get_next_thread_reply *req
     fprintf( stderr, " handle=%04x", req->handle );
 }
 
+static void dump_get_process_handle_info_request( const struct get_process_handle_info_request *req )
+{
+    fprintf( stderr, " handle=%04x", req->handle );
+}
+
+static void dump_get_process_handle_info_reply( const struct get_process_handle_info_reply *req )
+{
+    fprintf( stderr, " handle_count=%08x", req->handle_count );
+    dump_varargs_handle_infos( ", data=", cur_size );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -4762,6 +4773,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_suspend_process_request,
     (dump_func)dump_resume_process_request,
     (dump_func)dump_get_next_thread_request,
+    (dump_func)dump_get_process_handle_info_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -5040,6 +5052,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     NULL,
     NULL,
     (dump_func)dump_get_next_thread_reply,
+    (dump_func)dump_get_process_handle_info_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -5318,6 +5331,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "suspend_process",
     "resume_process",
     "get_next_thread",
+    "get_process_handle_info",
 };
 
 static const struct
-- 
2.35.1




More information about the wine-devel mailing list