Alexandre Julliard : ntdll: Add a helper function for applying page protection bytes with mprotect.

Alexandre Julliard julliard at winehq.org
Tue Sep 5 15:18:50 CDT 2017


Module: wine
Branch: master
Commit: 4069c4a4d1d8cc7dd9015b0c4caccc7513d597b1
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=4069c4a4d1d8cc7dd9015b0c4caccc7513d597b1

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Sep  5 14:28:27 2017 +0200

ntdll: Add a helper function for applying page protection bytes with mprotect.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/virtual.c | 96 ++++++++++++++++++----------------------------------
 1 file changed, 33 insertions(+), 63 deletions(-)

diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index d34fbed..80d83d8 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -707,6 +707,32 @@ static inline int mprotect_exec( void *base, size_t size, int unix_prot, unsigne
     return mprotect( base, size, unix_prot );
 }
 
+
+/***********************************************************************
+ *           mprotect_range
+ *
+ * Call mprotect on a page range, applying the protections from the per-page byte.
+ */
+static void mprotect_range( struct file_view *view, void *base, size_t size, BYTE set, BYTE clear )
+{
+    size_t i, count;
+    char *addr = base;
+    int prot, next;
+
+    prot = VIRTUAL_GetUnixProt( (get_page_vprot( view, addr ) & ~clear ) | set );
+    for (count = i = 1; i < size >> page_shift; i++, count++)
+    {
+        next = VIRTUAL_GetUnixProt( (get_page_vprot( view, addr + (count << page_shift) ) & ~clear) | set );
+        if (next == prot) continue;
+        mprotect_exec( addr, count << page_shift, prot, view->protect );
+        addr += count << page_shift;
+        prot = next;
+        count = 0;
+    }
+    if (count) mprotect_exec( addr, count << page_shift, prot, view->protect );
+}
+
+
 /***********************************************************************
  *           VIRTUAL_SetProt
  *
@@ -729,22 +755,8 @@ static BOOL VIRTUAL_SetProt( struct file_view *view, /* [in] Pointer to view */
     if (view->protect & VPROT_WRITEWATCH)
     {
         /* each page may need different protections depending on write watch flag */
-        UINT i, count;
-        char *addr = base;
-        int prot;
-
         set_page_vprot_bits( view, base, size, vprot & ~VPROT_WRITEWATCH, ~vprot & ~VPROT_WRITEWATCH );
-        unix_prot = VIRTUAL_GetUnixProt( get_page_vprot( view, addr ));
-        for (count = i = 1; i < size >> page_shift; i++, count++)
-        {
-            prot = VIRTUAL_GetUnixProt( get_page_vprot( view, addr + (count << page_shift) ));
-            if (prot == unix_prot) continue;
-            mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
-            addr += count << page_shift;
-            unix_prot = prot;
-            count = 0;
-        }
-        if (count) mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
+        mprotect_range( view, base, size, 0, 0 );
         VIRTUAL_DEBUG_DUMP_VIEW( view );
         return TRUE;
     }
@@ -777,22 +789,8 @@ static BOOL VIRTUAL_SetProt( struct file_view *view, /* [in] Pointer to view */
  */
 static void reset_write_watches( struct file_view *view, void *base, SIZE_T size )
 {
-    SIZE_T i, count;
-    int prot, unix_prot;
-    char *addr = base;
-
     set_page_vprot_bits( view, base, size, VPROT_WRITEWATCH, 0 );
-    unix_prot = VIRTUAL_GetUnixProt( get_page_vprot( view, addr ));
-    for (count = i = 1; i < size >> page_shift; i++, count++)
-    {
-        prot = VIRTUAL_GetUnixProt( get_page_vprot( view, addr + (count << page_shift) ));
-        if (prot == unix_prot) continue;
-        mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
-        addr += count << page_shift;
-        unix_prot = prot;
-        count = 0;
-    }
-    if (count) mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
+    mprotect_range( view, base, size, 0, 0 );
 }
 
 
@@ -1625,14 +1623,15 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
             if (vprot & VPROT_WRITEWATCH)
             {
                 set_page_vprot_bits( view, page, page_size, 0, VPROT_WRITEWATCH );
-                VIRTUAL_SetProt( view, page, page_size, get_page_vprot( view, page ));
+                mprotect_range( view, page, page_size, 0, 0 );
             }
             /* ignore fault if page is writable now */
             if (VIRTUAL_GetUnixProt( get_page_vprot( view, page )) & PROT_WRITE) ret = STATUS_SUCCESS;
         }
         if (!on_signal_stack && (vprot & VPROT_GUARD))
         {
-            VIRTUAL_SetProt( view, page, page_size, vprot & ~VPROT_GUARD );
+            set_page_vprot_bits( view, page, page_size, 0, VPROT_GUARD );
+            mprotect_range( view, page, page_size, 0, 0 );
             ret = STATUS_GUARD_PAGE_VIOLATION;
         }
     }
@@ -1835,7 +1834,7 @@ SIZE_T virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_
                     if (vprot & VPROT_WRITEWATCH)
                     {
                         set_page_vprot_bits( view, page, page_size, 0, VPROT_WRITEWATCH );
-                        VIRTUAL_SetProt( view, page, page_size, get_page_vprot( view, page ));
+                        mprotect_range( view, page, page_size, 0, 0 );
                     }
                     /* ignore fault if page is writable now */
                     if (!(VIRTUAL_GetUnixProt( get_page_vprot( view, page )) & PROT_WRITE))
@@ -1873,39 +1872,10 @@ void VIRTUAL_SetForceExec( BOOL enable )
 
         LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry )
         {
-            UINT i, count;
-            char *addr = view->base;
             BYTE commit = view->mapping ? VPROT_COMMITTED : 0;  /* file mappings are always accessible */
-            int unix_prot = VIRTUAL_GetUnixProt( get_page_vprot( view, addr ) | commit );
 
             if (view->protect & VPROT_NOEXEC) continue;
-            for (count = i = 1; i < view->size >> page_shift; i++, count++)
-            {
-                int prot = VIRTUAL_GetUnixProt( get_page_vprot( view, addr + (count << page_shift) ) | commit );
-                if (prot == unix_prot) continue;
-                if ((unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC))
-                {
-                    TRACE( "%s exec prot for %p-%p\n",
-                           force_exec_prot ? "enabling" : "disabling",
-                           addr, addr + (count << page_shift) - 1 );
-                    mprotect( addr, count << page_shift,
-                              unix_prot | (force_exec_prot ? PROT_EXEC : 0) );
-                }
-                addr += (count << page_shift);
-                unix_prot = prot;
-                count = 0;
-            }
-            if (count)
-            {
-                if ((unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC))
-                {
-                    TRACE( "%s exec prot for %p-%p\n",
-                           force_exec_prot ? "enabling" : "disabling",
-                           addr, addr + (count << page_shift) - 1 );
-                    mprotect( addr, count << page_shift,
-                              unix_prot | (force_exec_prot ? PROT_EXEC : 0) );
-                }
-            }
+            mprotect_range( view, view->base, view->size, commit, 0 );
         }
     }
     server_leave_uninterrupted_section( &csVirtual, &sigset );




More information about the wine-cvs mailing list