Alexandre Julliard : ntdll: Don' t do partial writes in virtual_uninterrupted_write_memory.
Alexandre Julliard
julliard at winehq.org
Wed Sep 6 14:45:36 CDT 2017
Module: wine
Branch: master
Commit: 3bfd7973a432450492607a4dfe54f774370e9318
URL: http://source.winehq.org/git/wine.git/?a=commit;h=3bfd7973a432450492607a4dfe54f774370e9318
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed Sep 6 17:16:25 2017 +0200
ntdll: Don't do partial writes in virtual_uninterrupted_write_memory.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/ntdll_misc.h | 2 +-
dlls/ntdll/signal_i386.c | 7 +++---
dlls/ntdll/virtual.c | 56 ++++++++++++++++--------------------------------
3 files changed, 23 insertions(+), 42 deletions(-)
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index c97b1e1..7b13448 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -171,7 +171,7 @@ extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_st
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 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 f33c43f..ab8d114 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1808,8 +1808,8 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
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) ) == sizeof(DWORD))
+ if (!virtual_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",
@@ -1856,8 +1856,7 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
stack, sizeof(stack) ) == sizeof(stack) &&
virtual_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]) ) == sizeof(stack[0]))
+ !virtual_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 9a69a15..a730417 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1907,54 +1907,36 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T
* permissions are checked before accessing each page, to ensure that no
* exceptions can happen.
*/
-SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
+NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size )
{
struct file_view *view;
sigset_t sigset;
- SIZE_T bytes_written = 0;
+ NTSTATUS ret = STATUS_ACCESS_VIOLATION;
- if (!size) return 0;
+ if (!size) return STATUS_SUCCESS;
server_enter_uninterrupted_section( &csVirtual, &sigset );
- if ((view = VIRTUAL_FindView( addr, size )))
+ if ((view = VIRTUAL_FindView( addr, size )) && !(view->protect & VPROT_SYSTEM))
{
- if (!(view->protect & VPROT_SYSTEM))
- {
- while (bytes_written < size)
- {
- void *page = ROUND_ADDR( addr, page_mask );
- BYTE vprot = get_page_vprot( page );
- SIZE_T block_size;
-
- /* If the page is not writable then check for write watches
- * before giving up. This can be done without raising a real
- * exception. Similar to virtual_handle_fault. */
- if (!(VIRTUAL_GetUnixProt( vprot ) & PROT_WRITE))
- {
- if (!(view->protect & VPROT_WRITEWATCH))
- break;
-
- if (vprot & VPROT_WRITEWATCH)
- {
- set_page_vprot_bits( page, page_size, 0, VPROT_WRITEWATCH );
- mprotect_range( view, page, page_size, 0, 0 );
- }
- /* ignore fault if page is writable now */
- if (!(VIRTUAL_GetUnixProt( get_page_vprot( page )) & PROT_WRITE))
- break;
- }
-
- block_size = min( size, page_size - ((UINT_PTR)addr & page_mask) );
- memcpy( addr, buffer, block_size );
+ char *page = ROUND_ADDR( addr, page_mask );
+ size_t i, total = ROUND_SIZE( addr, size );
- addr = (void *)((char *)addr + block_size);
- buffer = (const void *)((const char *)buffer + block_size);
- bytes_written += block_size;
- }
+ for (i = 0; i < total; i += page_size)
+ {
+ int prot = VIRTUAL_GetUnixProt( get_page_vprot( page + i ) & ~VPROT_WRITEWATCH );
+ if (!(prot & PROT_WRITE)) goto done;
}
+ if (view->protect & VPROT_WRITEWATCH) /* enable write access by clearing write watches */
+ {
+ set_page_vprot_bits( addr, size, 0, VPROT_WRITEWATCH );
+ mprotect_range( view, addr, size, 0, 0 );
+ }
+ memcpy( addr, buffer, size );
+ ret = STATUS_SUCCESS;
}
+done:
server_leave_uninterrupted_section( &csVirtual, &sigset );
- return bytes_written;
+ return ret;
}
More information about the wine-cvs
mailing list