[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