Alexandre Julliard : ntdll:
Force exec permissions on all mmaps unless the app is marked
NX-compatible .
Alexandre Julliard
julliard at wine.codeweavers.com
Wed Dec 6 05:48:55 CST 2006
Module: wine
Branch: master
Commit: 822be6c90fd8312e4a0689d964e7c9fb895503b1
URL: http://source.winehq.org/git/wine.git/?a=commit;h=822be6c90fd8312e4a0689d964e7c9fb895503b1
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Dec 5 15:42:29 2006 +0100
ntdll: Force exec permissions on all mmaps unless the app is marked NX-compatible.
---
dlls/ntdll/loader.c | 2 +
dlls/ntdll/ntdll_misc.h | 1 +
dlls/ntdll/virtual.c | 113 ++++++++++++++++++++++++++++++++++++++--------
3 files changed, 96 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 99c90c4..4d15779 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -2126,6 +2126,8 @@ void WINAPI LdrInitializeThunk( ULONG un
peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
version_init( wm->ldr.FullDllName.Buffer );
+ if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
+ VIRTUAL_SetForceExec( TRUE );
/* the main exe needs to be the first in the load order list */
RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 781afa5..a7ef8df 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -112,6 +112,7 @@ extern NTSTATUS DIR_get_unix_cwd( char *
/* virtual memory */
extern NTSTATUS VIRTUAL_HandleFault(LPCVOID addr);
extern BOOL VIRTUAL_HasMapping( LPCVOID addr );
+extern void VIRTUAL_SetForceExec( BOOL enable );
extern void VIRTUAL_UseLargeAddressSpace(void);
extern BOOL is_current_process( HANDLE handle );
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 573072e..54193ff 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -143,6 +143,7 @@ static void *user_space_limit = USER_SPA
static void *preload_reserve_start;
static void *preload_reserve_end;
static int use_locks;
+static int force_exec_prot; /* whether to force PROT_EXEC on all PROT_READ mmaps */
/***********************************************************************
@@ -162,6 +163,26 @@ static const char *VIRTUAL_GetProtStr( B
/***********************************************************************
+ * VIRTUAL_GetUnixProt
+ *
+ * Convert page protections to protection for mmap/mprotect.
+ */
+static int VIRTUAL_GetUnixProt( BYTE vprot )
+{
+ int prot = 0;
+ if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
+ {
+ if (vprot & VPROT_READ) prot |= PROT_READ;
+ if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
+ if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE;
+ if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
+ }
+ if (!prot) prot = PROT_NONE;
+ return prot;
+}
+
+
+/***********************************************************************
* VIRTUAL_DumpView
*/
static void VIRTUAL_DumpView( FILE_VIEW *view )
@@ -391,6 +412,7 @@ static NTSTATUS create_view( struct file
{
struct file_view *view;
struct list *ptr;
+ int unix_prot = VIRTUAL_GetUnixProt( vprot );
assert( !((UINT_PTR)base & page_mask) );
assert( !(size & page_mask) );
@@ -446,27 +468,13 @@ static NTSTATUS create_view( struct file
*view_ret = view;
VIRTUAL_DEBUG_DUMP_VIEW( view );
- return STATUS_SUCCESS;
-}
-
-/***********************************************************************
- * VIRTUAL_GetUnixProt
- *
- * Convert page protections to protection for mmap/mprotect.
- */
-static int VIRTUAL_GetUnixProt( BYTE vprot )
-{
- int prot = 0;
- if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
+ if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC))
{
- if (vprot & VPROT_READ) prot |= PROT_READ;
- if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
- if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE;
- if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
+ TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 );
+ mprotect( base, size, unix_prot | PROT_EXEC );
}
- if (!prot) prot = PROT_NONE;
- return prot;
+ return STATUS_SUCCESS;
}
@@ -555,12 +563,22 @@ static BOOL VIRTUAL_SetProt( FILE_VIEW *
size_t size, /* [in] Size in bytes */
BYTE vprot ) /* [in] Protections to use */
{
+ int unix_prot = VIRTUAL_GetUnixProt(vprot);
+
TRACE("%p-%p %s\n",
base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) );
- if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) ))
- return FALSE; /* FIXME: last error */
+ if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC))
+ {
+ TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 );
+ if (!mprotect( base, size, unix_prot | PROT_EXEC )) goto done;
+ /* exec + write may legitimately fail, in that case fall back to write only */
+ if (!(unix_prot & PROT_WRITE)) return FALSE;
+ }
+ if (mprotect( base, size, unix_prot )) return FALSE; /* FIXME: last error */
+
+done:
memset( view->prot + (((char *)base - (char *)view->base) >> page_shift),
vprot, size >> page_shift );
VIRTUAL_DEBUG_DUMP_VIEW( view );
@@ -1285,6 +1303,61 @@ BOOL VIRTUAL_HasMapping( LPCVOID addr )
/***********************************************************************
+ * VIRTUAL_SetForceExec
+ *
+ * Whether to force exec prot on all views.
+ */
+void VIRTUAL_SetForceExec( BOOL enable )
+{
+ struct file_view *view;
+
+ RtlEnterCriticalSection( &csVirtual );
+ if (!force_exec_prot != !enable) /* change all existing views */
+ {
+ force_exec_prot = enable;
+
+ LIST_FOR_EACH_ENTRY( view, &views_list, struct file_view, entry )
+ {
+ UINT i, count;
+ int unix_prot;
+ char *addr = view->base;
+ BYTE prot = view->prot[0];
+
+ for (count = i = 1; i < view->size >> page_shift; i++, count++)
+ {
+ if (view->prot[i] == prot) continue;
+ unix_prot = VIRTUAL_GetUnixProt( prot );
+ 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);
+ prot = view->prot[i];
+ count = 0;
+ }
+ if (count)
+ {
+ unix_prot = VIRTUAL_GetUnixProt( prot );
+ 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) );
+ }
+ }
+ }
+ }
+ RtlLeaveCriticalSection( &csVirtual );
+}
+
+
+/***********************************************************************
* VIRTUAL_UseLargeAddressSpace
*
* Increase the address space size for apps that support it.
More information about the wine-cvs
mailing list