[PATCH v2 0/4] MR11243: server: Add LPC port object infrastructure and port creation
This adds infrastructure needed to implement LPC and implements NtCreatePort and NtCreateWaitablePort Smaller MR based on the work at !10611 -- v2: ntdll/tests: Add LPC port creation tests ntdll/tests: Unconditionally enable port tests https://gitlab.winehq.org/wine/wine/-/merge_requests/11243
From: Rose Hellsing <rose@pinkro.se> Add the basic LPC port object type with support for creating named ports This implements the server-side create_lpc_port request which will be used by NtCreatePort and NtCreateWaitablePort --- server/Makefile.in | 1 + server/lpc_port.c | 213 ++++++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 12 +++ 3 files changed, 226 insertions(+) create mode 100644 server/lpc_port.c diff --git a/server/Makefile.in b/server/Makefile.in index 84a6bd74d9d..b6dc080896c 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -18,6 +18,7 @@ SOURCES = \ handle.c \ hook.c \ inproc_sync.c \ + lpc_port.c \ mach.c \ mailslot.c \ main.c \ diff --git a/server/lpc_port.c b/server/lpc_port.c new file mode 100644 index 00000000000..3c4ef23a4fb --- /dev/null +++ b/server/lpc_port.c @@ -0,0 +1,213 @@ +/* + * Server-side LPC port management + * + * Copyright 2026 Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "handle.h" +#include "thread.h" +#include "process.h" +#include "request.h" +#include "security.h" +#include "object.h" + +/* Port access rights */ +#define PORT_CONNECT 0x0001 +#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | PORT_CONNECT) + +/* Port types */ +#define PORT_TYPE_SERVER 0x01 /* Named port that server listens on */ + +/* Port flags */ +#define PORT_FLAG_WAITABLE 0x0001 + +/* Maximum message size */ +#define MAX_LPC_MESSAGE_SIZE 0x40000 + +static const WCHAR lpc_port_name[] = {'L','P','C',' ','P','o','r','t'}; + +struct type_descr lpc_port_type = +{ + { lpc_port_name, sizeof(lpc_port_name) }, /* name */ + PORT_ALL_ACCESS, /* valid_access */ + { /* mapping */ + STANDARD_RIGHTS_READ | PORT_CONNECT, + STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, + PORT_ALL_ACCESS + }, +}; + +/* LPC port object */ +struct lpc_port +{ + struct object obj; /* object header */ + unsigned int port_type; /* PORT_TYPE_* */ + unsigned int flags; /* PORT_FLAG_* */ + struct list msg_queue; /* list of pending messages */ + struct object *queue_event; /* event signaled when message arrives */ + unsigned int max_msg_len; /* maximum message length */ + unsigned int max_connect_info;/* maximum connection info length */ + struct object *wait_event; /* event for WaitForSingleObject (waitable ports) */ + struct process *server_process; /* server process (for named ports) */ +}; + +static void lpc_port_dump( struct object *obj, int verbose ); +static struct object *lpc_port_get_sync( struct object *obj ); +static void lpc_port_destroy( struct object *obj ); + +static const struct object_ops lpc_port_ops = +{ + sizeof(struct lpc_port), /* size */ + &lpc_port_type, /* type */ + lpc_port_dump, /* dump */ + NULL, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + lpc_port_get_sync, /* get_sync */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + lpc_port_destroy /* destroy */ +}; + +static struct lpc_port *create_lpc_port( struct object *root, const struct unicode_str *name, + unsigned int attr, unsigned int flags, + unsigned int max_msg_len, unsigned int max_connect_info, + const struct security_descriptor *sd ) +{ + struct lpc_port *port; + + if (max_msg_len > MAX_LPC_MESSAGE_SIZE) + max_msg_len = MAX_LPC_MESSAGE_SIZE; + if (max_connect_info > MAX_LPC_MESSAGE_SIZE) + max_connect_info = MAX_LPC_MESSAGE_SIZE; + + if ((port = create_named_object( root, &lpc_port_ops, name, attr, sd ))) + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + port->port_type = PORT_TYPE_SERVER; + port->flags = flags; + list_init( &port->msg_queue ); + port->queue_event = create_internal_sync( 0, 0 ); + port->max_msg_len = max_msg_len ? max_msg_len : MAX_LPC_MESSAGE_SIZE; + port->max_connect_info = max_connect_info ? max_connect_info : 256; + port->wait_event = NULL; + port->server_process = (struct process *)grab_object( current->process ); + + if (!port->queue_event) + { + release_object( port ); + return NULL; + } + + if (flags & PORT_FLAG_WAITABLE) + { + port->wait_event = create_internal_sync( 1, 0 ); + if (!port->wait_event) + { + release_object( port ); + return NULL; + } + } + } + } + return port; +} + +static void lpc_port_dump( struct object *obj, int verbose ) +{ + struct lpc_port *port = (struct lpc_port *)obj; + + assert( obj->ops == &lpc_port_ops ); + fprintf( stderr, "LPC Port type=%s flags=%04x max_msg=%u max_connect=%u\n", + port->port_type == PORT_TYPE_SERVER ? "SERVER" : "?", + port->flags, port->max_msg_len, port->max_connect_info ); +} + +static struct object *lpc_port_get_sync( struct object *obj ) +{ + struct lpc_port *port = (struct lpc_port *)obj; + + if (port->wait_event) + return grab_object( port->wait_event ); + + if (port->queue_event) + return grab_object( port->queue_event ); + + return NULL; +} + +static void lpc_port_destroy( struct object *obj ) +{ + struct lpc_port *port = (struct lpc_port *)obj; + + assert( obj->ops == &lpc_port_ops ); + + if (port->queue_event) release_object( port->queue_event ); + if (port->wait_event) release_object( port->wait_event ); + if (port->server_process) release_object( port->server_process ); +} + +/* Create an LPC port */ +DECL_HANDLER(create_lpc_port) +{ + struct lpc_port *port; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + + if (!objattr) return; + + if ((port = create_lpc_port( root, &name, objattr->attributes, req->flags, + req->max_msg_len, req->max_connect_info, sd ))) + { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, port, req->access, objattr->attributes ); + else + reply->handle = alloc_handle_no_access_check( current->process, port, + req->access, objattr->attributes ); + release_object( port ); + } + + if (root) release_object( root ); +} diff --git a/server/protocol.def b/server/protocol.def index 6c2ffc85aab..55296bd3c69 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4313,3 +4313,15 @@ enum inproc_sync_type data_size_t runtime_size; /* size of client runtime data */ VARARG(runtime,bytes); /* client runtime data */ @END + + +/* Create an LPC port */ +@REQ(create_lpc_port) + unsigned int access; /* desired access */ + unsigned int flags; /* port flags (waitable) */ + unsigned int max_msg_len; /* maximum message length */ + unsigned int max_connect_info; /* maximum connection info length */ + VARARG(objattr,object_attributes);/* object attributes */ +@REPLY + obj_handle_t handle; /* port handle */ +@END -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11243
From: Rose Hellsing <rose@pinkro.se> --- dlls/ntdll/ntdll.spec | 4 +-- dlls/ntdll/signal_arm64ec.c | 1 + dlls/ntdll/unix/sync.c | 61 +++++++++++++++++++++++++++++++++++-- dlls/wow64/sync.c | 22 +++++++++++++ include/winternl.h | 1 + 5 files changed, 85 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 0b6d9b2cbf4..24d6dc99f2b 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -212,7 +212,7 @@ @ stdcall -syscall NtCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall -syscall NtCreateTransaction(ptr long ptr ptr long long long long ptr ptr) @ stdcall -syscall NtCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr) -# @ stub NtCreateWaitablePort +@ stdcall -syscall NtCreateWaitablePort(ptr ptr long long long) @ stdcall -arch=i386 NtCurrentTeb() @ stdcall -syscall NtDebugActiveProcess(long long) @ stdcall -syscall NtDebugContinue(long ptr long) @@ -1292,7 +1292,7 @@ @ stdcall -private ZwCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) NtCreateToken @ stdcall -private ZwCreateTransaction(ptr long ptr ptr long long long long ptr ptr) NtCreateTransaction @ stdcall -private ZwCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr) NtCreateUserProcess -# @ stub ZwCreateWaitablePort +@ stdcall -private ZwCreateWaitablePort(ptr ptr long long long) NtCreateWaitablePort @ stdcall -private ZwDebugActiveProcess(long long) NtDebugActiveProcess @ stdcall -private ZwDebugContinue(long ptr long) NtDebugContinue @ stdcall -private ZwDelayExecution(long ptr) NtDelayExecution diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 140775d1a72..9359bd9ba69 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -415,6 +415,7 @@ DEFINE_SYSCALL(NtCreateTimer, (HANDLE *handle, ACCESS_MASK access, const OBJECT_ DEFINE_SYSCALL(NtCreateToken, (HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, TOKEN_TYPE type, LUID *token_id, LARGE_INTEGER *expire, TOKEN_USER *user, TOKEN_GROUPS *groups, TOKEN_PRIVILEGES *privs, TOKEN_OWNER *owner, TOKEN_PRIMARY_GROUP *group, TOKEN_DEFAULT_DACL *dacl, TOKEN_SOURCE *source)) DEFINE_SYSCALL(NtCreateTransaction, (HANDLE *handle, ACCESS_MASK mask, OBJECT_ATTRIBUTES *obj_attr, GUID *guid, HANDLE tm, ULONG options, ULONG isol_level, ULONG isol_flags, PLARGE_INTEGER timeout, UNICODE_STRING *description)) DEFINE_SYSCALL(NtCreateUserProcess, (HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr, ACCESS_MASK process_access, ACCESS_MASK thread_access, OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr, ULONG process_flags, ULONG thread_flags, RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info, PS_ATTRIBUTE_LIST *ps_attr)) +DEFINE_SYSCALL(NtCreateWaitablePort, (HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_lon, ULONG data_len, ULONG reserved)) DEFINE_SYSCALL(NtDebugActiveProcess, (HANDLE process, HANDLE debug)) DEFINE_SYSCALL(NtDebugContinue, (HANDLE handle, CLIENT_ID *client, NTSTATUS status)) DEFINE_SYSCALL(NtDelayExecution, (BOOLEAN alertable, const LARGE_INTEGER *timeout)) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index fbf054e9d93..ede54e5944c 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -3061,14 +3061,71 @@ NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ } +/* LPC port access rights */ +#define PORT_CONNECT 0x0001 +#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | PORT_CONNECT) + /*********************************************************************** * NtCreatePort (NTDLL.@) */ NTSTATUS WINAPI NtCreatePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len, ULONG data_len, ULONG *reserved ) { - FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle, attr, info_len, data_len, reserved ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + data_size_t len; + struct object_attributes *objattr; + + TRACE( "(%p,%p,%u,%u,%p)\n", handle, attr, info_len, data_len, reserved ); + + *handle = 0; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) + return ret; + + SERVER_START_REQ( create_lpc_port ) + { + req->access = PORT_ALL_ACCESS; + req->flags = 0; + req->max_msg_len = data_len; + req->max_connect_info = info_len; + wine_server_add_data( req, objattr, len ); + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + free( objattr ); + return ret; +} + + +/*********************************************************************** + * NtCreateWaitablePort (NTDLL.@) + */ +NTSTATUS WINAPI NtCreateWaitablePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len, + ULONG data_len, ULONG reserved ) +{ + unsigned int ret; + data_size_t len; + struct object_attributes *objattr; + + TRACE( "(%p,%p,%u,%u,%u)\n", handle, attr, info_len, data_len, reserved ); + + *handle = 0; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) + return ret; + + SERVER_START_REQ( create_lpc_port ) + { + req->access = PORT_ALL_ACCESS; + req->flags = 0x0001; /* PORT_FLAG_WAITABLE */ + req->max_msg_len = data_len; + req->max_connect_info = info_len; + wine_server_add_data( req, objattr, len ); + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + free( objattr ); + return ret; } diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index d5b52a5c815..2f0a617b70c 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -403,6 +403,28 @@ NTSTATUS WINAPI wow64_NtCreateSection( UINT *args ) } +/********************************************************************** + * wow64_NtCreateWaitablePort + */ +NTSTATUS WINAPI wow64_NtCreateWaitablePort( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + ULONG info_len = get_ulong( &args ); + ULONG data_len = get_ulong( &args ); + ULONG reserved = get_ulong( &args ); + + struct object_attr64 attr; + HANDLE handle = 0; + NTSTATUS status; + + *handle_ptr = 0; + status = NtCreateWaitablePort( &handle, objattr_32to64( &attr, attr32 ), info_len, data_len, reserved ); + put_handle( handle_ptr, handle ); + return status; +} + + /********************************************************************** * wow64_NtCreateSemaphore */ diff --git a/include/winternl.h b/include/winternl.h index 81dc3db2b74..24eb6c45405 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4785,6 +4785,7 @@ NTSYSAPI NTSTATUS WINAPI NtCreateTimer(HANDLE*, ACCESS_MASK, const OBJECT_ATTRI NTSYSAPI NTSTATUS WINAPI NtCreateToken(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,TOKEN_TYPE,PLUID,PLARGE_INTEGER,PTOKEN_USER,PTOKEN_GROUPS,PTOKEN_PRIVILEGES,PTOKEN_OWNER,PTOKEN_PRIMARY_GROUP,PTOKEN_DEFAULT_DACL,PTOKEN_SOURCE); NTSYSAPI NTSTATUS WINAPI NtCreateTransaction(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,LPGUID,HANDLE,ULONG,ULONG,ULONG,PLARGE_INTEGER,PUNICODE_STRING); NTSYSAPI NTSTATUS WINAPI NtCreateUserProcess(HANDLE*,HANDLE*,ACCESS_MASK,ACCESS_MASK,OBJECT_ATTRIBUTES*,OBJECT_ATTRIBUTES*,ULONG,ULONG,RTL_USER_PROCESS_PARAMETERS*,PS_CREATE_INFO*,PS_ATTRIBUTE_LIST*); +NTSYSAPI NTSTATUS WINAPI NtCreateWaitablePort(HANDLE*,OBJECT_ATTRIBUTES*,ULONG,ULONG,ULONG); NTSYSAPI NTSTATUS WINAPI NtDebugActiveProcess(HANDLE,HANDLE); NTSYSAPI NTSTATUS WINAPI NtDebugContinue(HANDLE,CLIENT_ID*,NTSTATUS); NTSYSAPI NTSTATUS WINAPI NtDelayExecution(BOOLEAN,const LARGE_INTEGER*); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11243
From: Rose Hellsing <rose@pinkro.se> Parts of LPC are now implemented, so these tests shouldn't be skipped as a whole anymore. --- dlls/ntdll/tests/port.c | 52 ++++++++++++----------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/dlls/ntdll/tests/port.c b/dlls/ntdll/tests/port.c index 80c60d09683..6dc8da6bf87 100644 --- a/dlls/ntdll/tests/port.c +++ b/dlls/ntdll/tests/port.c @@ -112,7 +112,6 @@ static const WCHAR PORTNAME[] = {'\\','M','y','P','o','r','t',0}; static UNICODE_STRING port; /* Function pointers for ntdll calls */ -static HMODULE hntdll = 0; static NTSTATUS (WINAPI *pNtCompleteConnectPort)(HANDLE); static NTSTATUS (WINAPI *pNtAcceptConnectPort)(PHANDLE,ULONG,PLPC_MESSAGE,ULONG, PLPC_SECTION_WRITE,PLPC_SECTION_READ); @@ -132,39 +131,6 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static BOOL is_wow64; -static BOOL init_function_ptrs(void) -{ - hntdll = LoadLibraryA("ntdll.dll"); - - if (!hntdll) - return FALSE; - - pNtCompleteConnectPort = (void *)GetProcAddress(hntdll, "NtCompleteConnectPort"); - pNtAcceptConnectPort = (void *)GetProcAddress(hntdll, "NtAcceptConnectPort"); - pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort"); - pNtReplyWaitReceivePort = (void *)GetProcAddress(hntdll, "NtReplyWaitReceivePort"); - pNtCreatePort = (void *)GetProcAddress(hntdll, "NtCreatePort"); - pNtRequestWaitReplyPort = (void *)GetProcAddress(hntdll, "NtRequestWaitReplyPort"); - pNtRequestPort = (void *)GetProcAddress(hntdll, "NtRequestPort"); - pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort"); - pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort"); - pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); - - if (!pNtCompleteConnectPort || !pNtAcceptConnectPort || - !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort || - !pNtRequestPort || !pNtRegisterThreadTerminatePort || - !pNtConnectPort || !pRtlInitUnicodeString) - { - todo_wine win_skip("Needed port functions are not available\n"); - FreeLibrary(hntdll); - return FALSE; - } - - pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); - if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; - return TRUE; -} - static void ProcessConnectionRequest(union lpc_message *LpcMessage, PHANDLE pAcceptPortHandle) { NTSTATUS status; @@ -184,7 +150,7 @@ static void ProcessConnectionRequest(union lpc_message *LpcMessage, PHANDLE pAcc status = pNtAcceptConnectPort(pAcceptPortHandle, 0, &LpcMessage->msg, 1, NULL, NULL); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status); - + status = pNtCompleteConnectPort(*pAcceptPortHandle); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status); } @@ -372,9 +338,21 @@ START_TEST(port) OBJECT_ATTRIBUTES obj; HANDLE port_handle; NTSTATUS status; + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); - if (!init_function_ptrs()) - return; + pNtCompleteConnectPort = (void *)GetProcAddress(hntdll, "NtCompleteConnectPort"); + pNtAcceptConnectPort = (void *)GetProcAddress(hntdll, "NtAcceptConnectPort"); + pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort"); + pNtReplyWaitReceivePort = (void *)GetProcAddress(hntdll, "NtReplyWaitReceivePort"); + pNtCreatePort = (void *)GetProcAddress(hntdll, "NtCreatePort"); + pNtRequestWaitReplyPort = (void *)GetProcAddress(hntdll, "NtRequestWaitReplyPort"); + pNtRequestPort = (void *)GetProcAddress(hntdll, "NtRequestPort"); + pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort"); + pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort"); + pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); + + pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); + if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; pRtlInitUnicodeString(&port, PORTNAME); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11243
From: Rose Hellsing <rose@pinkro.se> Add tests for NtCreatePort error paths including NULL/zero-length object attributes, NULL/empty port names, duplicate port names, and invalid maximum message/connect info sizes --- dlls/ntdll/tests/port.c | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/dlls/ntdll/tests/port.c b/dlls/ntdll/tests/port.c index 6dc8da6bf87..c2ad1eddb46 100644 --- a/dlls/ntdll/tests/port.c +++ b/dlls/ntdll/tests/port.c @@ -333,6 +333,88 @@ static void test_ports_server( HANDLE PortHandle ) HeapFree(GetProcessHeap(), 0, LpcMessage); } +static void test_create_port_errors(void) +{ + OBJECT_ATTRIBUTES obj; + HANDLE port_handle; + NTSTATUS status; + UNICODE_STRING name; + static const WCHAR ERR_PORT1[] = {'\\','E','r','r','P','o','r','t','1',0}; + static const WCHAR ERR_PORT2[] = {'\\','E','r','r','P','o','r','t','2',0}; + static const WCHAR ERR_PORT3[] = {'\\','E','r','r','P','o','r','t','3',0}; + + /* NULL object attributes */ + status = pNtCreatePort(&port_handle, NULL, 0, 0, 0); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER || status == STATUS_ACCESS_VIOLATION, + "Expected STATUS_SUCCESS, STATUS_INVALID_PARAMETER or STATUS_ACCESS_VIOLATION, got %08lx\n", status); + if (status == STATUS_SUCCESS) NtClose(port_handle); + + /* Zero-length object attributes */ + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = 0; + status = pNtCreatePort(&port_handle, &obj, 0, 0, 0); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_HANDLE, + "Expected STATUS_SUCCESS, STATUS_INVALID_PARAMETER or STATUS_INVALID_HANDLE, got %08lx\n", status); + if (status == STATUS_SUCCESS) NtClose(port_handle); + + /* Valid object attributes but NULL name */ + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = sizeof(OBJECT_ATTRIBUTES); + obj.ObjectName = NULL; + status = pNtCreatePort(&port_handle, &obj, 0, 0, 0); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER || status == STATUS_OBJECT_NAME_INVALID, + "Expected STATUS_SUCCESS, STATUS_INVALID_PARAMETER or STATUS_OBJECT_NAME_INVALID, got %08lx\n", status); + if (status == STATUS_SUCCESS) NtClose(port_handle); + + /* Empty name */ + pRtlInitUnicodeString(&name, L""); + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = sizeof(OBJECT_ATTRIBUTES); + obj.ObjectName = &name; + status = pNtCreatePort(&port_handle, &obj, 0, 0, 0); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER || status == STATUS_OBJECT_NAME_INVALID, + "Expected STATUS_SUCCESS, STATUS_INVALID_PARAMETER or STATUS_OBJECT_NAME_INVALID, got %08lx\n", status); + if (status == STATUS_SUCCESS) NtClose(port_handle); + + /* Max message size too large */ + pRtlInitUnicodeString(&name, ERR_PORT1); + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = sizeof(OBJECT_ATTRIBUTES); + obj.ObjectName = &name; + status = pNtCreatePort(&port_handle, &obj, 0x100001, 0, 0); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER || status == STATUS_SECTION_TOO_BIG || status == STATUS_OBJECT_NAME_COLLISION, + "Expected STATUS_SUCCESS, STATUS_INVALID_PARAMETER, STATUS_SECTION_TOO_BIG or STATUS_OBJECT_NAME_COLLISION, got %08lx\n", status); + if (status == STATUS_SUCCESS) NtClose(port_handle); + + /* Max connect info too large */ + pRtlInitUnicodeString(&name, ERR_PORT2); + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = sizeof(OBJECT_ATTRIBUTES); + obj.ObjectName = &name; + status = pNtCreatePort(&port_handle, &obj, 0, 0x100001, 0); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER || status == STATUS_SECTION_TOO_BIG || status == STATUS_OBJECT_NAME_COLLISION, + "Expected STATUS_SUCCESS, STATUS_INVALID_PARAMETER, STATUS_SECTION_TOO_BIG or STATUS_OBJECT_NAME_COLLISION, got %08lx\n", status); + if (status == STATUS_SUCCESS) NtClose(port_handle); + + /* Creating port with name that already exists */ + pRtlInitUnicodeString(&name, ERR_PORT3); + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = sizeof(OBJECT_ATTRIBUTES); + obj.ObjectName = &name; + status = pNtCreatePort(&port_handle, &obj, 100, 100, 0); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + if (status == STATUS_SUCCESS) + { + NTSTATUS status2; + HANDLE port_handle2; + status2 = pNtCreatePort(&port_handle2, &obj, 100, 100, 0); + ok(status2 == STATUS_OBJECT_NAME_COLLISION, + "Expected STATUS_OBJECT_NAME_COLLISION, got %08lx\n", status2); + NtClose(port_handle); + } +} + + START_TEST(port) { OBJECT_ATTRIBUTES obj; @@ -374,5 +456,7 @@ START_TEST(port) ok( WaitForSingleObject( thread, 10000 ) == 0, "thread didn't exit\n" ); CloseHandle(thread); } + test_create_port_errors(); + FreeLibrary(hntdll); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11243
participants (2)
-
Rose Hellsing -
Rose Hellsing (@axtlos)