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
Fix issue in ws2_32-WriteWatches patch which can cause exceptions on the signal stack.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
From 67e51503f973289b85c526eb05d76d78f7bd337e Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 3 Jan 2015 19:11:40 +0100
|
||||
Subject: ntdll: Handle write watches in virtual_uninterrupted_write_memory.
|
||||
|
||||
---
|
||||
dlls/ntdll/virtual.c | 30 +++++++++++++++++++++++++-----
|
||||
1 file changed, 25 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
|
||||
index 4c4c05d..8823164 100644
|
||||
--- a/dlls/ntdll/virtual.c
|
||||
+++ b/dlls/ntdll/virtual.c
|
||||
@@ -1730,12 +1730,32 @@ SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_
|
||||
{
|
||||
if (!(view->protect & VPROT_SYSTEM))
|
||||
{
|
||||
- void *page = ROUND_ADDR( addr, page_mask );
|
||||
- BYTE *p = view->prot + (((const char *)page - (const char *)view->base) >> page_shift);
|
||||
-
|
||||
- while (bytes_written < size && (VIRTUAL_GetUnixProt( *p++ ) & PROT_WRITE))
|
||||
+ while (bytes_written < size)
|
||||
{
|
||||
- SIZE_T block_size = min( size, page_size - ((UINT_PTR)addr & page_mask) );
|
||||
+ void *page = ROUND_ADDR( addr, page_mask );
|
||||
+ BYTE *p = view->prot + (((const char *)page - (const char *)view->base) >> page_shift);
|
||||
+ SIZE_T block_size;
|
||||
+
|
||||
+ /* If the page is not writeable then check for write watches
|
||||
+ * before giving up. This can be done without raising a real
|
||||
+ * exception. Similar to virtual_handle_fault, but we can't
|
||||
+ * handle guard pages here. */
|
||||
+ if (!(VIRTUAL_GetUnixProt( *p ) & PROT_WRITE))
|
||||
+ {
|
||||
+ if (!(view->protect & VPROT_WRITEWATCH))
|
||||
+ break;
|
||||
+
|
||||
+ if (*p & VPROT_WRITEWATCH)
|
||||
+ {
|
||||
+ *p &= ~VPROT_WRITEWATCH;
|
||||
+ VIRTUAL_SetProt( view, page, page_size, *p );
|
||||
+ }
|
||||
+ /* ignore fault if page is writable now */
|
||||
+ if (!(VIRTUAL_GetUnixProt( *p ) & PROT_WRITE))
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ block_size = min( size, page_size - ((UINT_PTR)addr & page_mask) );
|
||||
memcpy( addr, buffer, block_size );
|
||||
|
||||
addr = (void *)((char *)addr + block_size);
|
||||
--
|
||||
2.2.1
|
||||
|
@@ -0,0 +1,169 @@
|
||||
From 32e36972905ea820ac557c37b6d3a02dd32fd795 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 | 10 +++++-----
|
||||
dlls/ntdll/virtual.c | 34 ++++++++++++++++++++++------------
|
||||
include/winternl.h | 3 +++
|
||||
5 files changed, 34 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
|
||||
index 51de6e7..1e91089 100644
|
||||
--- a/dlls/ntdll/ntdll.spec
|
||||
+++ b/dlls/ntdll/ntdll.spec
|
||||
@@ -1430,6 +1430,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 b7ea6dc..e56e78b 100644
|
||||
--- a/dlls/ntdll/ntdll_misc.h
|
||||
+++ b/dlls/ntdll/ntdll_misc.h
|
||||
@@ -171,8 +171,6 @@ extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLS
|
||||
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err ) 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 SIZE_T 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 1a69bc0..de55c31 100644
|
||||
--- a/dlls/ntdll/signal_i386.c
|
||||
+++ b/dlls/ntdll/signal_i386.c
|
||||
@@ -1669,13 +1669,13 @@ 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,
|
||||
+ if (wine_uninterrupted_write_memory( (DWORD *)context->Esp + 1,
|
||||
&thunk_copy.t1.this, sizeof(DWORD) ) == sizeof(DWORD))
|
||||
{
|
||||
context->Eip = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func;
|
||||
@@ -1719,11 +1719,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,
|
||||
+ wine_uninterrupted_write_memory( (DWORD *)context->Esp + 1,
|
||||
&stack[0], sizeof(stack[0]) ) == sizeof(stack[0]))
|
||||
{
|
||||
context->Ecx = stack[0];
|
||||
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
|
||||
index 8823164..17792e1 100644
|
||||
--- a/dlls/ntdll/virtual.c
|
||||
+++ b/dlls/ntdll/virtual.c
|
||||
@@ -1672,13 +1672,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;
|
||||
@@ -1697,10 +1698,14 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
|
||||
while (bytes_read < size && (VIRTUAL_GetUnixProt( *p++ ) & 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;
|
||||
}
|
||||
}
|
||||
@@ -1711,13 +1716,14 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
- * virtual_uninterrupted_write_memory
|
||||
+ * wine_uninterrupted_write_memory (NTDLL.@)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
-SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
|
||||
+SIZE_T CDECL wine_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
|
||||
{
|
||||
struct file_view *view;
|
||||
sigset_t sigset;
|
||||
@@ -1756,10 +1762,14 @@ SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_
|
||||
}
|
||||
|
||||
block_size = min( size, page_size - ((UINT_PTR)addr & page_mask) );
|
||||
- memcpy( addr, buffer, block_size );
|
||||
|
||||
- addr = (void *)((char *)addr + block_size);
|
||||
- buffer = (const void *)((const char *)buffer + block_size);
|
||||
+ if (buffer)
|
||||
+ {
|
||||
+ memcpy( addr, buffer, block_size );
|
||||
+ buffer = (const void *)((const char *)buffer + block_size);
|
||||
+ }
|
||||
+
|
||||
+ addr = (void *)((char *)addr + block_size);
|
||||
bytes_written += block_size;
|
||||
}
|
||||
}
|
||||
diff --git a/include/winternl.h b/include/winternl.h
|
||||
index 1a694da..02dda9a 100644
|
||||
--- a/include/winternl.h
|
||||
+++ b/include/winternl.h
|
||||
@@ -2605,6 +2605,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 SIZE_T CDECL wine_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size );
|
||||
+
|
||||
|
||||
/***********************************************************************
|
||||
* Inline functions
|
||||
--
|
||||
2.2.1
|
||||
|
@@ -1,8 +1,8 @@
|
||||
From dc07ceb5dff69b2a306278d5d3254c18c98205df Mon Sep 17 00:00:00 2001
|
||||
From ae757e6bb862919e3b5a59bdb590555c462258ee 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
|
||||
write watches.
|
||||
write watches. (try 2)
|
||||
|
||||
Under specific circumstances Silverlight resets the write watch while the async
|
||||
WSARecv() operation is still pending:
|
||||
@@ -37,14 +37,14 @@ 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 | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
dlls/ws2_32/socket.c | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
|
||||
index b3db306..ef86b28 100644
|
||||
index a9ab0a5..9d94893 100644
|
||||
--- a/dlls/ws2_32/socket.c
|
||||
+++ b/dlls/ws2_32/socket.c
|
||||
@@ -1930,7 +1930,16 @@ static int WS2_recv( int fd, struct ws2_async *wsa )
|
||||
@@ -1930,7 +1930,17 @@ static int WS2_recv( int fd, struct ws2_async *wsa )
|
||||
|
||||
while ((n = recvmsg(fd, &hdr, wsa->flags)) == -1)
|
||||
{
|
||||
@@ -54,7 +54,8 @@ index b3db306..ef86b28 100644
|
||||
+ unsigned int i;
|
||||
+ for (i = wsa->first_iovec; i < wsa->n_iovecs; i++)
|
||||
+ {
|
||||
+ if (IsBadWritePtr( wsa->iovec[i].iov_base, wsa->iovec[i].iov_len ))
|
||||
+ struct iovec *iov = &wsa->iovec[i];
|
||||
+ if (wine_uninterrupted_write_memory( iov->iov_base, NULL, iov->iov_len ) < iov->iov_len)
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
@@ -63,5 +64,5 @@ index b3db306..ef86b28 100644
|
||||
}
|
||||
|
||||
--
|
||||
2.1.3
|
||||
2.2.1
|
||||
|
Reference in New Issue
Block a user