From: Rose Hellsing <rose@pinkro.se> Add LPC_MESSAGE32, LPC_SECTION_WRITE32 and LPC_SECTION_READ32 structures and conversion helpers, and use them in the LPC syscall thunks instead of passing 32-bit messages through unchanged. Update the port tests to distinguish between WOW64 detection (which gates NULL parameter tests that crash on Windows due to thunking) and the choice of LPC message layout. On Wine WOW64 the thunks now convert between the 32-bit and 64-bit layouts, so 32-bit callers use the native 24-byte header rather than the 64-bit layout required on Windows WOW64. --- dlls/ntdll/tests/port.c | 30 ++++++---- dlls/wow64/struct32.h | 29 +++++++++ dlls/wow64/sync.c | 120 +++++++++++++++++++++++++++---------- dlls/wow64/wow64_private.h | 90 ++++++++++++++++++++++++++++ 4 files changed, 227 insertions(+), 42 deletions(-) diff --git a/dlls/ntdll/tests/port.c b/dlls/ntdll/tests/port.c index cd62ee4a34c..9e1ec9240c2 100644 --- a/dlls/ntdll/tests/port.c +++ b/dlls/ntdll/tests/port.c @@ -134,6 +134,7 @@ static NTSTATUS (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static BOOL is_wow64; +static BOOL use_msg64; static BOOL init_function_ptrs(void) { @@ -167,6 +168,11 @@ static BOOL init_function_ptrs(void) pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; + /* On Wine WOW64, the wow64.dll thunks convert between 32-bit and 64-bit LPC_MESSAGE + * layouts, so 32-bit code uses the native LPC_MESSAGE (24-byte header). + * On Windows WOW64, the thunks pass through and the 32-bit caller must use the + * 64-bit layout (40-byte header) directly. */ + use_msg64 = is_wow64 && !winetest_platform_is_wine; return TRUE; } @@ -174,7 +180,7 @@ static void ProcessConnectionRequest(union lpc_message *LpcMessage, PHANDLE pAcc { NTSTATUS status; - if (is_wow64) + if (use_msg64) { ok(LpcMessage->msg64.MessageType == LPC_CONNECTION_REQUEST, "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg64.MessageType); @@ -189,7 +195,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); } @@ -198,7 +204,7 @@ static void ProcessLpcRequest(HANDLE PortHandle, union lpc_message *LpcMessage) { NTSTATUS status; - if (is_wow64) + if (use_msg64) { ok(LpcMessage->msg64.MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType); @@ -250,7 +256,7 @@ static DWORD WINAPI test_ports_client(LPVOID arg) status = pNtRegisterThreadTerminatePort(PortHandle); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status); - if (is_wow64) + if (use_msg64) { size = FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]); LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); @@ -321,7 +327,8 @@ static void test_ports_server( HANDLE PortHandle ) NTSTATUS status; BOOL done = FALSE; - size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN; + size = use_msg64 ? FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]) + : FIELD_OFFSET(LPC_MESSAGE, Data[MAX_MESSAGE_LEN]); LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); while (TRUE) @@ -334,7 +341,7 @@ static void test_ports_server( HANDLE PortHandle ) if ((status == STATUS_NOT_IMPLEMENTED) || (status == STATUS_INVALID_HANDLE)) return; - switch (is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType) + switch (use_msg64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType) { case LPC_CONNECTION_REQUEST: ProcessConnectionRequest(LpcMessage, &AcceptPortHandle); @@ -346,7 +353,7 @@ static void test_ports_server( HANDLE PortHandle ) break; case LPC_DATAGRAM: - if (is_wow64) + if (use_msg64) ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data); else @@ -361,7 +368,7 @@ static void test_ports_server( HANDLE PortHandle ) default: ok(FALSE, "Unexpected message: %d\n", - is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType); + use_msg64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType); break; } } @@ -493,7 +500,8 @@ static void test_zero_length_server(HANDLE PortHandle) NTSTATUS status; BOOL done = FALSE; - size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN; + size = use_msg64 ? FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]) + : FIELD_OFFSET(LPC_MESSAGE, Data[MAX_MESSAGE_LEN]); LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); while (!done) @@ -502,7 +510,7 @@ static void test_zero_length_server(HANDLE PortHandle) ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); if (status != STATUS_SUCCESS) break; - if (is_wow64) + if (use_msg64) { switch (LpcMessage->msg64.MessageType) { @@ -591,7 +599,7 @@ static DWORD WINAPI zero_length_client(LPVOID arg) ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); if (status != STATUS_SUCCESS) return 1; - if (is_wow64) + if (use_msg64) { size = FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]); LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index ba2bc02523f..3c6bcb9a743 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -803,6 +803,35 @@ typedef struct } DUMMYUNIONNAME4; } ALPC_PORT_MESSAGE32, *PALPC_PORT_MESSAGE32, ALPC_PORT_MESSAGE_HEADER32, *PALPC_PORT_MESSAGE_HEADER32; +typedef struct +{ + USHORT DataSize; + USHORT MessageSize; + USHORT MessageType; + USHORT VirtualRangesOffset; + CLIENT_ID32 ClientId; + ULONG MessageId; + ULONG SectionSize; + UCHAR Data[1]; +} LPC_MESSAGE32, *PLPC_MESSAGE32; + +typedef struct +{ + ULONG Length; + ULONG SectionHandle; + ULONG SectionOffset; + ULONG ViewSize; + ULONG ViewBase; + ULONG TargetViewBase; +} LPC_SECTION_WRITE32, *PLPC_SECTION_WRITE32; + +typedef struct +{ + ULONG Length; + ULONG ViewSize; + ULONG ViewBase; +} LPC_SECTION_READ32, *PLPC_SECTION_READ32; + typedef struct { ULONG AllocatedAttributes; diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index c4ba357979b..0bbf9257359 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -135,15 +135,25 @@ NTSTATUS WINAPI wow64_NtAcceptConnectPort( UINT *args ) { ULONG *handle_ptr = get_ptr( &args ); ULONG id = get_ulong( &args ); - LPC_MESSAGE *msg = get_ptr( &args ); + LPC_MESSAGE32 *msg32 = get_ptr( &args ); BOOLEAN accept = get_ulong( &args ); - LPC_SECTION_WRITE *write = get_ptr( &args ); - LPC_SECTION_READ *read = get_ptr( &args ); + LPC_SECTION_WRITE32 *write32 = get_ptr( &args ); + LPC_SECTION_READ32 *read32 = get_ptr( &args ); HANDLE handle = 0; NTSTATUS status; - - status = NtAcceptConnectPort( &handle, id, msg, accept, write, read ); + LPC_MESSAGE *msg; + LPC_SECTION_WRITE write; + LPC_SECTION_READ read; + + status = NtAcceptConnectPort( &handle, id, + lpc_message_32to64( &msg, msg32 ? (sizeof(*msg) + msg32->DataSize) : 0, msg32, TRUE ), + accept, + lpc_section_write_32to64( &write, write32 ), + lpc_section_read_32to64( &read, read32 ) ); + if (msg32 && msg) lpc_message_64to32( msg32, msg ); + if (write32) lpc_section_write_64to32( write32, &write ); + if (read32) lpc_section_read_64to32( read32, &read ); put_handle( handle_ptr, handle ); return status; } @@ -203,8 +213,8 @@ NTSTATUS WINAPI wow64_NtConnectPort( UINT *args ) ULONG *handle_ptr = get_ptr( &args ); UNICODE_STRING32 *name32 = get_ptr( &args ); SECURITY_QUALITY_OF_SERVICE *qos = get_ptr( &args ); - LPC_SECTION_WRITE *write = get_ptr( &args ); - LPC_SECTION_READ *read = get_ptr( &args ); + LPC_SECTION_WRITE32 *write32 = get_ptr( &args ); + LPC_SECTION_READ32 *read32 = get_ptr( &args ); ULONG *max_len = get_ptr( &args ); void *info = get_ptr( &args ); ULONG *info_len = get_ptr( &args ); @@ -212,10 +222,17 @@ NTSTATUS WINAPI wow64_NtConnectPort( UINT *args ) UNICODE_STRING name; HANDLE handle = 0; NTSTATUS status; + LPC_SECTION_WRITE write; + LPC_SECTION_READ read; unicode_str_32to64( &name, name32 ); - status = NtConnectPort( &handle, &name, qos, write, read, max_len, info, info_len ); + status = NtConnectPort( &handle, &name, qos, + lpc_section_write_32to64( &write, write32 ), + lpc_section_read_32to64( &read, read32 ), + max_len, info, info_len ); + if (write32) lpc_section_write_64to32( write32, &write ); + if (read32) lpc_section_read_64to32( read32, &read ); put_handle( handle_ptr, handle ); return status; } @@ -558,10 +575,11 @@ NTSTATUS WINAPI wow64_NtDuplicateObject( UINT *args ) NTSTATUS WINAPI wow64_NtImpersonateClientOfPort( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *msg = get_ptr( &args ); + LPC_MESSAGE32 *msg32 = get_ptr( &args ); - FIXME( "%p %p: stub\n", handle, msg ); - return STATUS_NOT_IMPLEMENTED; + LPC_MESSAGE *msg; + + return NtImpersonateClientOfPort( handle, lpc_message_32to64( &msg, msg32 ? (sizeof(*msg) + msg32->DataSize) : 0, msg32, TRUE ) ); } @@ -571,9 +589,14 @@ NTSTATUS WINAPI wow64_NtImpersonateClientOfPort( UINT *args ) NTSTATUS WINAPI wow64_NtListenPort( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *msg = get_ptr( &args ); + LPC_MESSAGE32 *msg32 = get_ptr( &args ); + + LPC_MESSAGE *msg; + NTSTATUS status; - return NtListenPort( handle, msg ); + status = NtListenPort( handle, lpc_message_32to64( &msg, sizeof(*msg) + 0x1000, msg32, FALSE ) ); + if (!status && msg32) lpc_message_64to32( msg32, msg ); + return status; } @@ -1308,7 +1331,7 @@ NTSTATUS WINAPI wow64_NtReleaseSemaphore( UINT *args ) NTSTATUS WINAPI wow64_NtReadRequestData( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *request = get_ptr( &args ); + LPC_MESSAGE32 *request = get_ptr( &args ); ULONG id = get_ulong( &args ); void *buffer = get_ptr( &args ); ULONG len = get_ulong( &args ); @@ -1325,9 +1348,11 @@ NTSTATUS WINAPI wow64_NtReadRequestData( UINT *args ) NTSTATUS WINAPI wow64_NtReplyPort( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *reply = get_ptr( &args ); + LPC_MESSAGE32 *reply32 = get_ptr( &args ); + + LPC_MESSAGE *reply; - return NtReplyPort( handle, reply ); + return NtReplyPort( handle, lpc_message_32to64( &reply, reply32 ? (sizeof(*reply) + reply32->DataSize) : 0, reply32, TRUE ) ); } @@ -1338,10 +1363,18 @@ NTSTATUS WINAPI wow64_NtReplyWaitReceivePort( UINT *args ) { HANDLE handle = get_handle( &args ); ULONG *id = get_ptr( &args ); - LPC_MESSAGE *reply = get_ptr( &args ); - LPC_MESSAGE *msg = get_ptr( &args ); + LPC_MESSAGE32 *reply32 = get_ptr( &args ); + LPC_MESSAGE32 *msg32 = get_ptr( &args ); + + LPC_MESSAGE *reply; + LPC_MESSAGE *msg; + NTSTATUS status; - return NtReplyWaitReceivePort( handle, id, reply, msg ); + status = NtReplyWaitReceivePort( handle, id, + lpc_message_32to64( &reply, reply32 ? (sizeof(*reply) + reply32->DataSize) : 0, reply32, TRUE ), + lpc_message_32to64( &msg, sizeof(*msg) + 0x1000, msg32, FALSE ) ); + if (!status && msg32) lpc_message_64to32( msg32, msg ); + return status; } @@ -1352,11 +1385,20 @@ NTSTATUS WINAPI wow64_NtReplyWaitReceivePortEx( UINT *args ) { HANDLE handle = get_handle( &args ); ULONG *id = get_ptr( &args ); - LPC_MESSAGE *reply = get_ptr( &args ); - LPC_MESSAGE *msg = get_ptr( &args ); + LPC_MESSAGE32 *reply32 = get_ptr( &args ); + LPC_MESSAGE32 *msg32 = get_ptr( &args ); LARGE_INTEGER *timeout = get_ptr( &args ); - return NtReplyWaitReceivePortEx( handle, id, reply, msg, timeout ); + LPC_MESSAGE *reply; + LPC_MESSAGE *msg; + NTSTATUS status; + + status = NtReplyWaitReceivePortEx( handle, id, + lpc_message_32to64( &reply, reply32 ? (sizeof(*reply) + reply32->DataSize) : 0, reply32, TRUE ), + lpc_message_32to64( &msg, sizeof(*msg) + 0x1000, msg32, FALSE ), + timeout ); + if (!status && msg32) lpc_message_64to32( msg32, msg ); + return status; } @@ -1366,9 +1408,11 @@ NTSTATUS WINAPI wow64_NtReplyWaitReceivePortEx( UINT *args ) NTSTATUS WINAPI wow64_NtRequestPort( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *msg = get_ptr( &args ); + LPC_MESSAGE32 *msg32 = get_ptr( &args ); - return NtRequestPort( handle, msg ); + LPC_MESSAGE *msg; + + return NtRequestPort( handle, lpc_message_32to64( &msg, msg32 ? (sizeof(*msg) + msg32->DataSize) : 0, msg32, TRUE ) ); } @@ -1378,10 +1422,18 @@ NTSTATUS WINAPI wow64_NtRequestPort( UINT *args ) NTSTATUS WINAPI wow64_NtRequestWaitReplyPort( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *msg_in = get_ptr( &args ); - LPC_MESSAGE *msg_out = get_ptr( &args ); + LPC_MESSAGE32 *msg_in32 = get_ptr( &args ); + LPC_MESSAGE32 *msg_out32 = get_ptr( &args ); + + LPC_MESSAGE *msg_in; + LPC_MESSAGE *msg_out; + NTSTATUS status; - return NtRequestWaitReplyPort( handle, msg_in, msg_out ); + status = NtRequestWaitReplyPort( handle, + lpc_message_32to64( &msg_in, msg_in32 ? (sizeof(*msg_in) + msg_in32->DataSize) : 0, msg_in32, TRUE ), + lpc_message_32to64( &msg_out, sizeof(*msg_out) + 0x1000, msg_out32, FALSE ) ); + if (!status && msg_out32) lpc_message_64to32( msg_out32, msg_out ); + return status; } @@ -1405,9 +1457,9 @@ NTSTATUS WINAPI wow64_NtSecureConnectPort( UINT *args ) ULONG *handle_ptr = get_ptr( &args ); UNICODE_STRING32 *name32 = get_ptr( &args ); SECURITY_QUALITY_OF_SERVICE *qos = get_ptr( &args ); - LPC_SECTION_WRITE *write = get_ptr( &args ); + LPC_SECTION_WRITE32 *write32 = get_ptr( &args ); SID *sid = get_ptr( &args ); - LPC_SECTION_READ *read = get_ptr( &args ); + LPC_SECTION_READ32 *read32 = get_ptr( &args ); ULONG *max_len = get_ptr( &args ); void *info = get_ptr( &args ); ULONG *info_len = get_ptr( &args ); @@ -1415,9 +1467,15 @@ NTSTATUS WINAPI wow64_NtSecureConnectPort( UINT *args ) UNICODE_STRING name; HANDLE handle = 0; NTSTATUS status; + LPC_SECTION_WRITE write; + LPC_SECTION_READ read; status = NtSecureConnectPort( &handle, unicode_str_32to64( &name, name32 ), - qos, write, sid, read, max_len, info, info_len ); + qos, lpc_section_write_32to64( &write, write32 ), + sid, lpc_section_read_32to64( &read, read32 ), + max_len, info, info_len ); + if (write32) lpc_section_write_64to32( write32, &write ); + if (read32) lpc_section_read_64to32( read32, &read ); put_handle( handle_ptr, handle ); return status; } @@ -1862,7 +1920,7 @@ NTSTATUS WINAPI wow64_NtWaitForSingleObject( UINT *args ) NTSTATUS WINAPI wow64_NtWriteRequestData( UINT *args ) { HANDLE handle = get_handle( &args ); - LPC_MESSAGE *request = get_ptr( &args ); + LPC_MESSAGE32 *request = get_ptr( &args ); ULONG id = get_ulong( &args ); void *buffer = get_ptr( &args ); ULONG len = get_ulong( &args ); diff --git a/dlls/wow64/wow64_private.h b/dlls/wow64/wow64_private.h index 2ac3e51f1f0..00476b9a71a 100644 --- a/dlls/wow64/wow64_private.h +++ b/dlls/wow64/wow64_private.h @@ -487,6 +487,96 @@ static inline ALPC_MESSAGE_ATTRIBUTES32 *alpc_port_message_attributes_64to32( AL return out; } +static inline LPC_MESSAGE *lpc_message_32to64( LPC_MESSAGE **out, SIZE_T out_msg_size, + const LPC_MESSAGE32 *in, BOOL copy_msg ) +{ + LPC_MESSAGE *msg; + + if (!in || !(msg = Wow64AllocateTemp( out_msg_size ))) + { + *out = NULL; + return NULL; + } + + if (!copy_msg) goto done; + + msg->DataSize = in->DataSize; + msg->MessageSize = FIELD_OFFSET( LPC_MESSAGE, Data ) + in->DataSize; + msg->MessageType = in->MessageType; + msg->VirtualRangesOffset = in->VirtualRangesOffset; + client_id_32to64( &msg->ClientId, &in->ClientId ); + msg->MessageId = in->MessageId; + msg->SectionSize = in->SectionSize; + memcpy( (unsigned char *)msg + FIELD_OFFSET( LPC_MESSAGE, Data ), + (const unsigned char *)in + FIELD_OFFSET( LPC_MESSAGE32, Data ), in->DataSize ); +done: + *out = msg; + return msg; +} + +static inline LPC_MESSAGE32 *lpc_message_64to32( LPC_MESSAGE32 *out, const LPC_MESSAGE *in ) +{ + if (!in) return NULL; + + out->DataSize = in->DataSize; + out->MessageSize = FIELD_OFFSET( LPC_MESSAGE32, Data ) + in->DataSize; + out->MessageType = in->MessageType; + out->VirtualRangesOffset = in->VirtualRangesOffset; + out->ClientId.UniqueProcess = HandleToUlong( in->ClientId.UniqueProcess ); + out->ClientId.UniqueThread = HandleToUlong( in->ClientId.UniqueThread ); + out->MessageId = in->MessageId; + out->SectionSize = in->SectionSize; + memcpy( (unsigned char *)out + FIELD_OFFSET( LPC_MESSAGE32, Data ), + (const unsigned char *)in + FIELD_OFFSET( LPC_MESSAGE, Data ), in->DataSize ); + return out; +} + +static inline LPC_SECTION_WRITE *lpc_section_write_32to64( LPC_SECTION_WRITE *out, + const LPC_SECTION_WRITE32 *in ) +{ + if (!in) return NULL; + out->Length = sizeof(*out); + out->SectionHandle = LongToHandle( in->SectionHandle ); + out->SectionOffset = in->SectionOffset; + out->ViewSize = in->ViewSize; + out->ViewBase = ULongToPtr( in->ViewBase ); + out->TargetViewBase = ULongToPtr( in->TargetViewBase ); + return out; +} + +static inline LPC_SECTION_WRITE32 *lpc_section_write_64to32( LPC_SECTION_WRITE32 *out, + const LPC_SECTION_WRITE *in ) +{ + if (!in) return NULL; + out->Length = sizeof(*out); + out->SectionHandle = HandleToUlong( in->SectionHandle ); + out->SectionOffset = in->SectionOffset; + out->ViewSize = in->ViewSize; + out->ViewBase = PtrToUlong( in->ViewBase ); + out->TargetViewBase = PtrToUlong( in->TargetViewBase ); + return out; +} + +static inline LPC_SECTION_READ *lpc_section_read_32to64( LPC_SECTION_READ *out, + const LPC_SECTION_READ32 *in ) +{ + if (!in) return NULL; + out->Length = sizeof(*out); + out->ViewSize = in->ViewSize; + out->ViewBase = ULongToPtr( in->ViewBase ); + return out; +} + +static inline LPC_SECTION_READ32 *lpc_section_read_64to32( LPC_SECTION_READ32 *out, + const LPC_SECTION_READ *in ) +{ + if (!in) return NULL; + out->Length = sizeof(*out); + out->ViewSize = in->ViewSize; + out->ViewBase = PtrToUlong( in->ViewBase ); + return out; +} + static inline TOKEN_USER *token_user_32to64( TOKEN_USER *out, const TOKEN_USER32 *in ) { out->User.Sid = ULongToPtr( in->User.Sid ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10611