Largely based on Nikolay Sivov's original patch and !3096. The files modified from running make_requests and make_specfile have been omitted.
-- v5: ntdll: Implement NtGetNextProcess.
From: Etaash Mathamsetty etaash.mathamsetty@gmail.com
--- dlls/ntdll/tests/om.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 62659fc8cb4..bfeb76fa88a 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -65,6 +65,7 @@ static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATT static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, void *, ULONG, FILE_INFORMATION_CLASS); static NTSTATUS (WINAPI *pNtOpenProcess)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const CLIENT_ID * ); static NTSTATUS (WINAPI *pNtCreateDebugObject)( HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG ); +static NTSTATUS (WINAPI *pNtGetNextProcess)(HANDLE process, ACCESS_MASK access, ULONG attributes, ULONG flags, HANDLE *handle); static NTSTATUS (WINAPI *pNtGetNextThread)(HANDLE process, HANDLE thread, ACCESS_MASK access, ULONG attributes, ULONG flags, HANDLE *handle); static NTSTATUS (WINAPI *pNtOpenProcessToken)(HANDLE,DWORD,HANDLE*); @@ -3156,6 +3157,32 @@ static void test_null_in_object_name(void) skip("Limited access to \Registry\Machine\Software key, skipping the tests\n"); }
+static void test_get_next_process(void) +{ + NTSTATUS status; + HANDLE handle; + + if (!pNtGetNextProcess) + { + win_skip("NtGetNextProcess is not available.\n"); + return; + } + + status = pNtGetNextProcess(0, PROCESS_QUERY_LIMITED_INFORMATION, OBJ_INHERIT, 0, &handle); + ok(!status, "Unexpected status %#lx.\n", status); + pNtClose(handle); + + /* Reversed search only supported in recent enough Win10 */ + status = pNtGetNextProcess(0, PROCESS_QUERY_LIMITED_INFORMATION, OBJ_INHERIT, 1, &handle); + ok(!status || broken(status == STATUS_INVALID_PARAMETER), "Unexpected status %#lx.\n", status); + if (status) + pNtClose(handle); + + status = pNtGetNextProcess(0, PROCESS_QUERY_LIMITED_INFORMATION, OBJ_INHERIT, 2, &handle); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %#lx.\n", status); +} + + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -3194,6 +3221,7 @@ START_TEST(om) pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); pNtOpenProcess = (void *)GetProcAddress(hntdll, "NtOpenProcess"); pNtCreateDebugObject = (void *)GetProcAddress(hntdll, "NtCreateDebugObject"); + pNtGetNextProcess = (void *)GetProcAddress(hntdll, "NtGetNextProcess"); pNtGetNextThread = (void *)GetProcAddress(hntdll, "NtGetNextThread"); pNtOpenProcessToken = (void *)GetProcAddress(hntdll, "NtOpenProcessToken"); pNtOpenThreadToken = (void *)GetProcAddress(hntdll, "NtOpenThreadToken"); @@ -3215,6 +3243,7 @@ START_TEST(om) test_token(); test_duplicate_object(); test_object_types(); + test_get_next_process(); test_get_next_thread(); test_globalroot(); test_object_identity();
From: Etaash Mathamsetty etaash.mathamsetty@gmail.com
--- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/unix/process.c | 28 ++++++++++++++++++++++++++++ dlls/wow64/process.c | 21 +++++++++++++++++++++ include/winternl.h | 1 + server/process.c | 38 ++++++++++++++++++++++++++++++++++++++ server/protocol.def | 9 +++++++++ 6 files changed, 98 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 1908a089d44..3644c666fce 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -230,6 +230,7 @@ @ stdcall -norelay -syscall NtGetContextThread(long ptr) @ stdcall -syscall NtGetCurrentProcessorNumber() # @ stub NtGetDevicePowerState +@ stdcall -syscall NtGetNextProcess(ptr long long long ptr) @ stdcall -syscall NtGetNextThread(ptr ptr long long long ptr) @ stdcall -syscall NtGetNlsSectionPtr(long long long ptr ptr) # @ stub NtGetPlugPlayEvent diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 71eab55920d..fb82a0a622c 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1768,6 +1768,34 @@ NTSTATUS WINAPI NtResumeProcess( HANDLE handle ) return ret; }
+/********************************************************************** + * NtGetNextProcess (NTDLL.@) + */ +NTSTATUS WINAPI NtGetNextProcess( HANDLE process, ACCESS_MASK access, ULONG attributes, + ULONG flags, HANDLE *handle ) +{ + unsigned int ret; + HANDLE ret_handle; + + TRACE( "process %p, access %#x, attributes %#x, flags %#x, handle %p.\n", + process, (int)access, (int)attributes, (int)flags, handle ); + + + SERVER_START_REQ( get_next_process ) + { + req->last = wine_server_obj_handle( process ); + req->access = access; + req->attributes = attributes; + req->flags = flags; + if (!(ret = wine_server_call( req ))) ret_handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + + *handle = ret_handle; + return ret; +} + +
/********************************************************************** * NtDebugActiveProcess (NTDLL.@) diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 817926d0f13..6fe997bb0b4 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -435,6 +435,27 @@ NTSTATUS WINAPI wow64_NtFlushProcessWriteBuffers( UINT *args ) }
+/********************************************************************** + * wow64_NtGetNextProcess + */ +NTSTATUS WINAPI wow64_NtGetNextProcess( UINT *args ) +{ + HANDLE process = get_handle( &args ); + ACCESS_MASK access = get_ulong( &args ); + ULONG attributes = get_ulong( &args ); + ULONG flags = get_ulong( &args ); + ULONG *handle_ptr = get_ptr( &args ); + + HANDLE handle = 0; + NTSTATUS status; + + *handle_ptr = 0; + status = NtGetNextProcess( process, access, attributes, flags, &handle ); + put_handle( handle_ptr, handle ); + return status; +} + + /********************************************************************** * wow64_NtGetNextThread */ diff --git a/include/winternl.h b/include/winternl.h index ff8756211a1..ab79940e8e7 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4411,6 +4411,7 @@ NTSYSAPI NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG); NTSYSAPI NTSTATUS WINAPI NtFsControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG); NTSYSAPI NTSTATUS WINAPI NtGetContextThread(HANDLE,CONTEXT*); NTSYSAPI ULONG WINAPI NtGetCurrentProcessorNumber(void); +NTSYSAPI NTSTATUS WINAPI NtGetNextProcess(HANDLE,ACCESS_MASK,ULONG,ULONG,HANDLE*); NTSYSAPI NTSTATUS WINAPI NtGetNextThread(HANDLE,HANDLE,ACCESS_MASK,ULONG,ULONG,HANDLE*); NTSYSAPI NTSTATUS WINAPI NtGetNlsSectionPtr(ULONG,ULONG,void*,void**,SIZE_T*); NTSYSAPI NTSTATUS WINAPI NtGetPlugPlayEvent(ULONG,ULONG,PVOID,ULONG); diff --git a/server/process.c b/server/process.c index a0d5ea64d97..70b3a80a28c 100644 --- a/server/process.c +++ b/server/process.c @@ -1390,6 +1390,44 @@ DECL_HANDLER(get_new_process_info) } }
+/* Itererate processes using global process list */ +DECL_HANDLER(get_next_process) +{ + struct process *process = NULL; + struct list *ptr; + + if (req->flags > 1) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (!req->last) + { + ptr = req->flags ? list_tail( &process_list ) : list_head( &process_list ); + } + else + { + if (!(process = get_process_from_handle( req->last, 0 ))) + return; + ptr = req->flags ? list_prev( &process_list, &process->entry ) + : list_next( &process_list, &process->entry ); + release_object( process ); + } + + while (ptr) + { + process = LIST_ENTRY( ptr, struct process, entry ); + if ((reply->handle = alloc_handle( current->process, process, req->access, req->attributes ))) + break; + ptr = req->flags ? list_prev( &process_list, &process->entry ) + : list_next( &process_list, &process->entry ); + } + + if (!reply->handle) + set_error( STATUS_NO_MORE_ENTRIES ); +} + /* Retrieve the new process startup info */ DECL_HANDLER(get_startup_info) { diff --git a/server/protocol.def b/server/protocol.def index 5d60e7fcda3..267ca60182c 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3873,6 +3873,15 @@ struct handle_info obj_handle_t handle; /* process handle */ @END
+/* Itererate processes using global process list */ +@REQ(get_next_process) + obj_handle_t last; /* process handle to start with */ + unsigned int access; /* desired access for returned handle */ + unsigned int attributes; /* returned handle attributes */ + unsigned int flags; /* controls iteration direction */ +@REPLY + obj_handle_t handle; /* next process handle */ +@END
/* Iterate thread list for process */ @REQ(get_next_thread)
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=140861
Your paranoid android.
=== debian11 (build log) ===
/usr/bin/i686-w64-mingw32-ld: tmp65ad030b/ntdll-00000000.spec.o:fake:(.edata+0x308): undefined reference to `NtGetNextProcess@20' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debian11b (build log) ===
/usr/bin/x86_64-w64-mingw32-ld: tmp6574a60b/ntdll-00000000.spec.o:fake:(.edata+0x304): undefined reference to `NtGetNextProcess' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
On Wed Dec 6 20:00:30 2023 +0000, Paul Gofman wrote:
I doubt it should be req->access here but hard to say for sure without some testing.
the original patch and the thread version also uses 0 here, so I will stick with that for now until I wrote more tests.
On Wed Dec 6 20:00:30 2023 +0000, Etaash Mathamsetty wrote:
the original patch and the thread version also uses 0 here, so I will stick with that for now until I wrote more tests.
Right, access mask you pass in is for returned handle. To access current point of iteration it's probably enough to use PROCESS_QUERY_LIMITED_INFORMATION. If it works without this access, we might use 0 I suppose.