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