You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-09-12 18:50:20 -07:00
Rebase against 44cb0afb2571984bda8ca1fa084a50c1fc04ac71.
This commit is contained in:
@@ -1,162 +0,0 @@
|
||||
From 6d426bf5815052c59127d85383a82e080a00f21b Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 3 Jan 2015 20:07:08 +0100
|
||||
Subject: ntdll: Expose wine_uninterrupted_[read|write]_memory as exports.
|
||||
|
||||
---
|
||||
dlls/ntdll/ntdll.spec | 4 ++++
|
||||
dlls/ntdll/ntdll_misc.h | 2 --
|
||||
dlls/ntdll/signal_i386.c | 12 ++++++------
|
||||
dlls/ntdll/virtual.c | 26 ++++++++++++++++----------
|
||||
include/winternl.h | 3 +++
|
||||
5 files changed, 29 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
|
||||
index 69bfe923234..5d5fa5b5c4e 100644
|
||||
--- a/dlls/ntdll/ntdll.spec
|
||||
+++ b/dlls/ntdll/ntdll.spec
|
||||
@@ -1495,6 +1495,10 @@
|
||||
# signal handling
|
||||
@ cdecl __wine_set_signal_handler(long ptr)
|
||||
|
||||
+# Virtual memory management
|
||||
+@ cdecl wine_uninterrupted_read_memory(ptr ptr long)
|
||||
+@ cdecl wine_uninterrupted_write_memory(ptr ptr long)
|
||||
+
|
||||
# Filesystem
|
||||
@ cdecl wine_nt_to_unix_file_name(ptr ptr long long)
|
||||
@ cdecl wine_unix_to_nt_file_name(ptr ptr)
|
||||
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
|
||||
index 3358119657d..af142a31c70 100644
|
||||
--- a/dlls/ntdll/ntdll_misc.h
|
||||
+++ b/dlls/ntdll/ntdll_misc.h
|
||||
@@ -173,8 +173,6 @@ extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLS
|
||||
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
-extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
-extern NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
extern void VIRTUAL_SetForceExec( BOOL enable ) DECLSPEC_HIDDEN;
|
||||
extern void virtual_release_address_space(void) DECLSPEC_HIDDEN;
|
||||
extern void virtual_set_large_address_space(void) DECLSPEC_HIDDEN;
|
||||
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
|
||||
index ab8d1144472..94b06214568 100644
|
||||
--- a/dlls/ntdll/signal_i386.c
|
||||
+++ b/dlls/ntdll/signal_i386.c
|
||||
@@ -1802,14 +1802,14 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
union atl_thunk thunk_copy;
|
||||
SIZE_T thunk_len;
|
||||
|
||||
- thunk_len = virtual_uninterrupted_read_memory( thunk, &thunk_copy, sizeof(*thunk) );
|
||||
+ thunk_len = wine_uninterrupted_read_memory( thunk, &thunk_copy, sizeof(*thunk) );
|
||||
if (!thunk_len) return FALSE;
|
||||
|
||||
if (thunk_len >= sizeof(thunk_copy.t1) && thunk_copy.t1.movl == 0x042444c7 &&
|
||||
thunk_copy.t1.jmp == 0xe9)
|
||||
{
|
||||
- if (!virtual_uninterrupted_write_memory( (DWORD *)context->Esp + 1,
|
||||
- &thunk_copy.t1.this, sizeof(DWORD) ))
|
||||
+ if (!wine_uninterrupted_write_memory( (DWORD *)context->Esp + 1,
|
||||
+ &thunk_copy.t1.this, sizeof(DWORD) ))
|
||||
{
|
||||
context->Eip = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func;
|
||||
TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n",
|
||||
@@ -1852,11 +1852,11 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
thunk_copy.t5.inst2 == 0x0460)
|
||||
{
|
||||
DWORD func, stack[2];
|
||||
- if (virtual_uninterrupted_read_memory( (DWORD *)context->Esp,
|
||||
+ if (wine_uninterrupted_read_memory( (DWORD *)context->Esp,
|
||||
stack, sizeof(stack) ) == sizeof(stack) &&
|
||||
- virtual_uninterrupted_read_memory( (DWORD *)stack[1] + 1,
|
||||
+ wine_uninterrupted_read_memory( (DWORD *)stack[1] + 1,
|
||||
&func, sizeof(DWORD) ) == sizeof(DWORD) &&
|
||||
- !virtual_uninterrupted_write_memory( (DWORD *)context->Esp + 1, &stack[0], sizeof(stack[0]) ))
|
||||
+ !wine_uninterrupted_write_memory( (DWORD *)context->Esp + 1, &stack[0], sizeof(stack[0]) ))
|
||||
{
|
||||
context->Ecx = stack[0];
|
||||
context->Eax = stack[1];
|
||||
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
|
||||
index a73041706f7..cb3b9aad385 100644
|
||||
--- a/dlls/ntdll/virtual.c
|
||||
+++ b/dlls/ntdll/virtual.c
|
||||
@@ -1862,13 +1862,14 @@ BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
- * virtual_uninterrupted_read_memory
|
||||
+ * wine_uninterrupted_read_memory (NTDLL.@)
|
||||
*
|
||||
* Similar to NtReadVirtualMemory, but without wineserver calls. Moreover
|
||||
* permissions are checked before accessing each page, to ensure that no
|
||||
- * exceptions can happen.
|
||||
+ * exceptions can happen. When a NULL pointer is passed as buffer the
|
||||
+ * permissions are only checked and no actual memcpy is performed.
|
||||
*/
|
||||
-SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size )
|
||||
+SIZE_T CDECL wine_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size )
|
||||
{
|
||||
struct file_view *view;
|
||||
sigset_t sigset;
|
||||
@@ -1886,10 +1887,14 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
|
||||
while (bytes_read < size && (VIRTUAL_GetUnixProt( get_page_vprot( page )) & PROT_READ))
|
||||
{
|
||||
SIZE_T block_size = min( size, page_size - ((UINT_PTR)addr & page_mask) );
|
||||
- memcpy( buffer, addr, block_size );
|
||||
|
||||
- addr = (const void *)((const char *)addr + block_size);
|
||||
- buffer = (void *)((char *)buffer + block_size);
|
||||
+ if (buffer)
|
||||
+ {
|
||||
+ memcpy( buffer, addr, block_size );
|
||||
+ buffer = (void *)((char *)buffer + block_size);
|
||||
+ }
|
||||
+
|
||||
+ addr = (const void *)((const char *)addr + block_size);
|
||||
bytes_read += block_size;
|
||||
page += page_size;
|
||||
}
|
||||
@@ -1901,13 +1906,14 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
- * virtual_uninterrupted_write_memory
|
||||
+ * wine_uninterrupted_write_memory
|
||||
*
|
||||
* Similar to NtWriteVirtualMemory, but without wineserver calls. Moreover
|
||||
* permissions are checked before accessing each page, to ensure that no
|
||||
- * exceptions can happen.
|
||||
+ * exceptions can happen. When a NULL pointer is passed as buffer the
|
||||
+ * permissions are only checked and no actual memcpy is performed.
|
||||
*/
|
||||
-NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
|
||||
+NTSTATUS CDECL wine_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
|
||||
{
|
||||
struct file_view *view;
|
||||
sigset_t sigset;
|
||||
@@ -1931,7 +1937,7 @@ NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZ
|
||||
set_page_vprot_bits( addr, size, 0, VPROT_WRITEWATCH );
|
||||
mprotect_range( view, addr, size, 0, 0 );
|
||||
}
|
||||
- memcpy( addr, buffer, size );
|
||||
+ if (buffer) memcpy( addr, buffer, size );
|
||||
ret = STATUS_SUCCESS;
|
||||
}
|
||||
done:
|
||||
diff --git a/include/winternl.h b/include/winternl.h
|
||||
index 3d60baa1f98..3ff6c38d6dc 100644
|
||||
--- a/include/winternl.h
|
||||
+++ b/include/winternl.h
|
||||
@@ -2790,6 +2790,9 @@ NTSYSAPI NTSTATUS CDECL wine_nt_to_unix_file_name( const UNICODE_STRING *nameW,
|
||||
UINT disposition, BOOLEAN check_case );
|
||||
NTSYSAPI NTSTATUS CDECL wine_unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt );
|
||||
|
||||
+NTSYSAPI SIZE_T CDECL wine_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size );
|
||||
+NTSYSAPI NTSTATUS CDECL wine_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size );
|
||||
+
|
||||
|
||||
/***********************************************************************
|
||||
* Inline functions
|
||||
--
|
||||
2.14.1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 7c4a78a160ee6b8a23a1eac779901faae5cb2335 Mon Sep 17 00:00:00 2001
|
||||
From cab68a82435dfc0cd55f65dca6febae250681f14 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Fri, 21 Nov 2014 12:22:46 +0100
|
||||
Subject: ws2_32: Avoid race-conditions of async WSARecv() operations with
|
||||
@@ -37,41 +37,116 @@ Based on the code it looks like we could savely remove the write-watch check
|
||||
at the beginning of WS2_recv_base, which might make the application think
|
||||
that data is immediately available.
|
||||
---
|
||||
dlls/ws2_32/socket.c | 15 ++++++++++++++-
|
||||
dlls/ntdll/ntdll.spec | 3 +++
|
||||
dlls/ntdll/virtual.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/ws2_32/socket.c | 4 +++-
|
||||
dlls/ws2_32/tests/sock.c | 11 +++--------
|
||||
2 files changed, 17 insertions(+), 9 deletions(-)
|
||||
4 files changed, 54 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
|
||||
index 68d7f22b192..b4acd5e6feb 100644
|
||||
--- a/dlls/ntdll/ntdll.spec
|
||||
+++ b/dlls/ntdll/ntdll.spec
|
||||
@@ -1491,6 +1491,9 @@
|
||||
# signal handling
|
||||
@ cdecl __wine_set_signal_handler(long ptr)
|
||||
|
||||
+# Virtal memory management
|
||||
+@ cdecl wine_virtual_locked_recvmsg(long ptr long)
|
||||
+
|
||||
# Filesystem
|
||||
@ cdecl wine_nt_to_unix_file_name(ptr ptr long long)
|
||||
@ cdecl wine_unix_to_nt_file_name(ptr ptr)
|
||||
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
|
||||
index 2cdcca8a599..7e22a8a9bcf 100644
|
||||
--- a/dlls/ntdll/virtual.c
|
||||
+++ b/dlls/ntdll/virtual.c
|
||||
@@ -41,6 +41,9 @@
|
||||
#ifdef HAVE_SYS_SYSINFO_H
|
||||
# include <sys/sysinfo.h>
|
||||
#endif
|
||||
+#ifdef HAVE_SYS_SOCKET_H
|
||||
+# include <sys/socket.h>
|
||||
+#endif
|
||||
#ifdef HAVE_VALGRIND_VALGRIND_H
|
||||
# include <valgrind/valgrind.h>
|
||||
#endif
|
||||
@@ -1913,6 +1916,48 @@ ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset )
|
||||
}
|
||||
|
||||
|
||||
+/***********************************************************************
|
||||
+ * virtual_locked_recvmsg
|
||||
+ */
|
||||
+ssize_t CDECL wine_virtual_locked_recvmsg( int sockfd, struct msghdr *msg, int flags )
|
||||
+{
|
||||
+ sigset_t sigset;
|
||||
+ BOOL has_write_watch = FALSE;
|
||||
+ int err = EFAULT;
|
||||
+ int i;
|
||||
+
|
||||
+ ssize_t size, ret = recvmsg( sockfd, msg, flags );
|
||||
+ if (ret != -1 || errno != EFAULT) return ret;
|
||||
+
|
||||
+ server_enter_uninterrupted_section( &csVirtual, &sigset );
|
||||
+
|
||||
+ for (i = 0; i < msg->msg_iovlen; i++)
|
||||
+ {
|
||||
+ struct iovec *iov = &msg->msg_iov[i];
|
||||
+ if (check_write_access( iov->iov_base, iov->iov_len, &has_write_watch ))
|
||||
+ {
|
||||
+ while (i--) update_write_watches( msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, 0 );
|
||||
+ goto done;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ size = ret = recvmsg( sockfd, msg, flags );
|
||||
+ err = errno;
|
||||
+
|
||||
+ if (!has_write_watch) goto done;
|
||||
+ for (i = 0; i < msg->msg_iovlen; i++)
|
||||
+ {
|
||||
+ struct iovec *iov = &msg->msg_iov[i];
|
||||
+ update_write_watches( iov->iov_base, iov->iov_len, min( max( 0, size ), iov->iov_len ));
|
||||
+ size -= iov->iov_len;
|
||||
+ }
|
||||
+
|
||||
+done:
|
||||
+ server_leave_uninterrupted_section( &csVirtual, &sigset );
|
||||
+ errno = err;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_is_valid_code_address
|
||||
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
|
||||
index 681f340bc6d..ac356035cc6 100644
|
||||
index 681f340bc6d..e97b8ebfe69 100644
|
||||
--- a/dlls/ws2_32/socket.c
|
||||
+++ b/dlls/ws2_32/socket.c
|
||||
@@ -2358,7 +2358,20 @@ static int WS2_recv( int fd, struct ws2_async *wsa, int flags )
|
||||
@@ -263,6 +263,8 @@ static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPWSABUF lpControlBuffer );
|
||||
|
||||
while ((n = recvmsg(fd, &hdr, flags)) == -1)
|
||||
+extern ssize_t CDECL wine_virtual_locked_recvmsg( int sockfd, struct msghdr *msg, int flags );
|
||||
+
|
||||
/* critical section to protect some non-reentrant net function */
|
||||
static CRITICAL_SECTION csWSgetXXXbyYYY;
|
||||
static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||
@@ -2356,7 +2358,7 @@ static int WS2_recv( int fd, struct ws2_async *wsa, int flags )
|
||||
hdr.msg_flags = 0;
|
||||
#endif
|
||||
|
||||
- while ((n = recvmsg(fd, &hdr, flags)) == -1)
|
||||
+ while ((n = wine_virtual_locked_recvmsg(fd, &hdr, flags)) == -1)
|
||||
{
|
||||
- if (errno != EINTR)
|
||||
+ if (errno == EFAULT)
|
||||
+ {
|
||||
+ unsigned int i;
|
||||
+ for (i = wsa->first_iovec; i < wsa->n_iovecs; i++)
|
||||
+ {
|
||||
+ struct iovec *iov = &wsa->iovec[i];
|
||||
+ if (wine_uninterrupted_write_memory( iov->iov_base, NULL, iov->iov_len ) != STATUS_SUCCESS)
|
||||
+ {
|
||||
+ errno = EFAULT;
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ else if (errno != EINTR)
|
||||
if (errno != EINTR)
|
||||
return -1;
|
||||
}
|
||||
|
||||
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
|
||||
index 02f7473215d..e1e37404b72 100644
|
||||
index 7b0cc322dad..12b90e979f9 100644
|
||||
--- a/dlls/ws2_32/tests/sock.c
|
||||
+++ b/dlls/ws2_32/tests/sock.c
|
||||
@@ -6962,18 +6962,15 @@ static void test_write_watch(void)
|
||||
@@ -6963,18 +6963,15 @@ static void test_write_watch(void)
|
||||
send(src, "test message", sizeof("test message"), 0);
|
||||
|
||||
ret = GetOverlappedResult( (HANDLE)dest, &ov, &bytesReturned, TRUE );
|
||||
@@ -91,7 +166,7 @@ index 02f7473215d..e1e37404b72 100644
|
||||
|
||||
memset( base, 0, size );
|
||||
count = 64;
|
||||
@@ -6984,7 +6981,6 @@ static void test_write_watch(void)
|
||||
@@ -6985,7 +6982,6 @@ static void test_write_watch(void)
|
||||
bufs[1].len = 0x4000;
|
||||
bufs[1].buf = base + 0x2000;
|
||||
ret = WSARecvFrom( dest, bufs, 2, NULL, &flags, &addr, &addr_len, &ov, NULL);
|
||||
@@ -99,7 +174,7 @@ index 02f7473215d..e1e37404b72 100644
|
||||
ok(ret == SOCKET_ERROR && GetLastError() == ERROR_IO_PENDING,
|
||||
"WSARecv failed - %d error %d\n", ret, GetLastError());
|
||||
|
||||
@@ -6992,7 +6988,6 @@ static void test_write_watch(void)
|
||||
@@ -6993,7 +6989,6 @@ static void test_write_watch(void)
|
||||
ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
ok( count == 5, "wrong count %lu\n", count );
|
||||
@@ -107,7 +182,7 @@ index 02f7473215d..e1e37404b72 100644
|
||||
ok( !base[0], "data set\n" );
|
||||
|
||||
send(src, "test message", sizeof("test message"), 0);
|
||||
@@ -7006,7 +7001,7 @@ static void test_write_watch(void)
|
||||
@@ -7007,7 +7002,7 @@ static void test_write_watch(void)
|
||||
count = 64;
|
||||
ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
@@ -116,7 +191,7 @@ index 02f7473215d..e1e37404b72 100644
|
||||
|
||||
memset( base, 0, size );
|
||||
count = 64;
|
||||
@@ -7035,7 +7030,7 @@ static void test_write_watch(void)
|
||||
@@ -7036,7 +7031,7 @@ static void test_write_watch(void)
|
||||
count = 64;
|
||||
ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
|
||||
Reference in New Issue
Block a user