Module: wine Branch: master Commit: 3bfd7973a432450492607a4dfe54f774370e9318 URL: http://source.winehq.org/git/wine.git/?a=commit;h=3bfd7973a432450492607a4dfe...
Author: Alexandre Julliard julliard@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@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; }