ntdll-WRITECOPY: Fix some additional issues, disable this patch by default since it might trigger additional Wine bugs.

This commit is contained in:
Sebastian Lackner 2014-10-04 03:24:43 +02:00
parent 7f43d57d01
commit e273769702
11 changed files with 474 additions and 283 deletions

View File

@ -742,21 +742,28 @@ ntdll-Pipe_SpecialCharacters.ok:
# Patchset ntdll-WRITECOPY
# |
# | Included patches:
# | * Change WRITECOPY memory protection to WRITE on first write. [rev 2, by Michael Müller]
# | * Change WRITECOPY memory protection to WRITE on first write. [rev 3, by Michael Müller]
# |
# | This patchset fixes the following Wine bugs:
# | * [#29384] Voobly expects correct handling of WRITECOPY memory protection
# |
# | Modified files:
# | * dlls/kernel32/tests/virtual.c, dlls/ntdll/loader.c, dlls/ntdll/ntdll_misc.h, dlls/ntdll/signal_arm.c,
# | dlls/ntdll/signal_arm64.c, dlls/ntdll/signal_i386.c, dlls/ntdll/signal_powerpc.c, dlls/ntdll/signal_x86_64.c,
# | dlls/ntdll/thread.c, dlls/ntdll/virtual.c
# | * dlls/advapi32/crypt.c, dlls/kernel32/tests/virtual.c, dlls/ntdll/loader.c, dlls/ntdll/ntdll_misc.h, dlls/ntdll/server.c,
# | dlls/ntdll/signal_arm.c, dlls/ntdll/signal_arm64.c, dlls/ntdll/signal_i386.c, dlls/ntdll/signal_powerpc.c,
# | dlls/ntdll/signal_x86_64.c, dlls/ntdll/thread.c, dlls/ntdll/virtual.c
# |
.INTERMEDIATE: ntdll-WRITECOPY.ok
ntdll-WRITECOPY.ok:
$(call APPLY_FILE,ntdll-WRITECOPY/0001-ntdll-Change-WRITECOPY-memory-protection-to-WRITE-on.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0001-ntdll-Trigger-write-watches-before-passing-userdata-.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0002-advapi-Trigger-write-watches-before-passing-userdata.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0003-ntdll-Fix-handling-of-page-fault-if-a-guard-page-and.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0004-ntdll-Avoid-race-condition-if-two-threads-trigger-a-.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0005-ntdll-Wait-until-builtin-dlls-are-unloaded-before-re.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0006-ntdll-Setup-a-temporary-signal-handler-during-proces.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0007-ntdll-Properly-handle-PAGE_WRITECOPY-protection.patch)
$(call APPLY_FILE,ntdll-WRITECOPY/0008-ntdll-Only-enable-true-WRITECOPY-protection-when-a-s.patch)
@( \
echo '+ { "ntdll-WRITECOPY", "Michael Müller", "Change WRITECOPY memory protection to WRITE on first write. [rev 2]" },'; \
echo '+ { "ntdll-WRITECOPY", "Michael Müller", "Change WRITECOPY memory protection to WRITE on first write. [rev 3]" },'; \
) > ntdll-WRITECOPY.ok
# Patchset ntdll-loader_EntryPoint

View File

@ -1,276 +0,0 @@
From fd0671380f0770d071dfc203034e58b6e6f86aff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Wed, 1 Oct 2014 00:43:05 +0200
Subject: ntdll: Change WRITECOPY memory protection to WRITE on first write
access.
---
dlls/kernel32/tests/virtual.c | 12 ++---------
dlls/ntdll/loader.c | 2 +-
dlls/ntdll/ntdll_misc.h | 1 +
dlls/ntdll/signal_arm.c | 6 ++++++
dlls/ntdll/signal_arm64.c | 6 ++++++
dlls/ntdll/signal_i386.c | 47 +++++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/signal_powerpc.c | 6 ++++++
dlls/ntdll/signal_x86_64.c | 6 ++++++
dlls/ntdll/thread.c | 1 +
dlls/ntdll/virtual.c | 26 ++++++++++++++++--------
10 files changed, 94 insertions(+), 19 deletions(-)
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index 0955d30..5b81e38 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -2038,11 +2038,7 @@ todo_wine
SetLastError(0xdeadbeef);
ret = VirtualQuery(base, &info, sizeof(info));
ok(ret, "VirtualQuery failed %d\n", GetLastError());
- /* FIXME: remove the condition below once Wine is fixed */
- if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
- todo_wine ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
- else
- ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
+ ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
}
}
else
@@ -2056,11 +2052,7 @@ todo_wine
SetLastError(0xdeadbeef);
ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
- /* FIXME: remove the condition below once Wine is fixed */
- if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
- todo_wine ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
- else
- ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
+ ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
}
UnmapViewOfFile(base);
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 18ae29c..f0fb1f2 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -2641,8 +2641,8 @@ static void free_modref( WINE_MODREF *wm )
free_tls_slot( &wm->ldr );
RtlReleaseActivationContext( wm->ldr.ActivationContext );
- NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
if (wm->ldr.Flags & LDR_WINE_INTERNAL) wine_dll_unload( wm->ldr.SectionHandle );
+ NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
if (cached_modref == wm) cached_modref = NULL;
RtlFreeUnicodeString( &wm->ldr.FullDllName );
RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 4370084..53e6b55 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -67,6 +67,7 @@ extern NTSTATUS signal_alloc_thread( TEB **teb ) DECLSPEC_HIDDEN;
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_process(void) DECLSPEC_HIDDEN;
+extern void signal_init_early(void) DECLSPEC_HIDDEN;
extern void version_init( const WCHAR *appname ) DECLSPEC_HIDDEN;
extern void debug_init(void) DECLSPEC_HIDDEN;
extern HANDLE thread_init(void) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index e3ae7bd..1d79b3d 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -930,6 +930,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* __wine_enter_vm86 (NTDLL.@)
diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index 8c8f7af..483bc85 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -791,6 +791,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* __wine_enter_vm86 (NTDLL.@)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 12aa5a4..d24e3bf 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1949,6 +1949,30 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
/**********************************************************************
+ * segv_handler_early
+ *
+ * Handler for SIGSEGV and related errors. Used only during the initialization
+ * of the process to handle virtual faults.
+ */
+static void segv_handler_early( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+ WORD fs, gs;
+ ucontext_t *context = sigcontext;
+ init_handler( sigcontext, &fs, &gs );
+
+ switch(get_trap_code(context))
+ {
+ case TRAP_x86_PAGEFLT: /* Page fault */
+ if (!virtual_handle_fault( siginfo->si_addr, (get_error_code(context) >> 1) & 0x09 ))
+ return;
+ /* fall-through */
+ default:
+ WINE_ERR( "Got unexpected trap %d during process initialization\n", get_trap_code(context) );
+ break;
+ }
+}
+
+/**********************************************************************
* segv_handler
*
* Handler for SIGSEGV and related errors.
@@ -2371,6 +2395,29 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+ struct sigaction sig_act;
+
+ sig_act.sa_mask = server_block_set;
+ sig_act.sa_flags = SA_SIGINFO | SA_RESTART;
+#ifdef SA_ONSTACK
+ sig_act.sa_flags |= SA_ONSTACK;
+#endif
+#ifdef __ANDROID__
+ sig_act.sa_flags |= SA_RESTORER;
+ sig_act.sa_restorer = rt_sigreturn;
+#endif
+ sig_act.sa_sigaction = segv_handler_early;
+ if (sigaction( SIGSEGV, &sig_act, NULL ) == -1)
+ {
+ perror("sigaction");
+ exit(1);
+ }
+}
#ifdef __HAVE_VM86
/**********************************************************************
diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c
index 0fca342..5d1d756 100644
--- a/dlls/ntdll/signal_powerpc.c
+++ b/dlls/ntdll/signal_powerpc.c
@@ -1048,6 +1048,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* __wine_enter_vm86 (NTDLL.@)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 05581c2..22da5d6 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2576,6 +2576,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* RtlAddFunctionTable (NTDLL.@)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index c8461b0..a2937c2 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -221,6 +221,7 @@ HANDLE thread_init(void)
static struct debug_info debug_info; /* debug info for initial thread */
virtual_init();
+ signal_init_early();
/* reserve space for shared user data */
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 4819d2d..47654f4 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -179,8 +179,13 @@ static int VIRTUAL_GetUnixProt( BYTE vprot )
{
if (vprot & VPROT_READ) prot |= PROT_READ;
if (vprot & VPROT_WRITE) prot |= PROT_WRITE | PROT_READ;
- if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ;
if (vprot & VPROT_EXEC) prot |= PROT_EXEC | PROT_READ;
+#if defined(__i386__)
+ if (vprot & VPROT_WRITECOPY) prot &= ~PROT_WRITE;
+#else
+ /* FIXME: Architecture needs implementation of signal_init_early. */
+ if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ;
+#endif
if (vprot & VPROT_WRITEWATCH) prot &= ~PROT_WRITE;
}
if (!prot) prot = PROT_NONE;
@@ -1522,21 +1527,26 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err )
{
void *page = ROUND_ADDR( addr, page_mask );
BYTE *vprot = &view->prot[((const char *)page - (const char *)view->base) >> page_shift];
- if (*vprot & VPROT_GUARD)
- {
- VIRTUAL_SetProt( view, page, page_size, *vprot & ~VPROT_GUARD );
- ret = STATUS_GUARD_PAGE_VIOLATION;
- }
- if ((err & EXCEPTION_WRITE_FAULT) && (view->protect & VPROT_WRITEWATCH))
+ if (err & EXCEPTION_WRITE_FAULT)
{
- if (*vprot & VPROT_WRITEWATCH)
+ if ((view->protect & VPROT_WRITEWATCH) && (*vprot & VPROT_WRITEWATCH))
{
*vprot &= ~VPROT_WRITEWATCH;
VIRTUAL_SetProt( view, page, page_size, *vprot );
}
+ if (*vprot & VPROT_WRITECOPY)
+ {
+ *vprot = (*vprot & ~VPROT_WRITECOPY) | VPROT_WRITE;
+ VIRTUAL_SetProt( view, page, page_size, *vprot );
+ }
/* ignore fault if page is writable now */
if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS;
}
+ if (*vprot & VPROT_GUARD)
+ {
+ VIRTUAL_SetProt( view, page, page_size, *vprot & ~VPROT_GUARD );
+ ret = STATUS_GUARD_PAGE_VIOLATION;
+ }
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
return ret;
--
1.9.1

View File

@ -0,0 +1,32 @@
From 9dd581f7b7013b9bc26894292f0fffc493caebdd Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 4 Oct 2014 02:35:44 +0200
Subject: ntdll: Trigger write watches before passing userdata pointer to
wait_reply.
---
dlls/ntdll/server.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index aabda4f..4d5d4ba 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -292,6 +292,14 @@ unsigned int wine_server_call( void *req_ptr )
sigset_t old_set;
unsigned int ret;
+ /* trigger write watches, otherwise read() might return EFAULT */
+ if (req->u.req.request_header.reply_size &&
+ !virtual_check_buffer_for_write( req->reply_data, req->u.req.request_header.reply_size ))
+ {
+ ret = STATUS_ACCESS_VIOLATION;
+ return ret;
+ }
+
pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
ret = send_request( req );
if (!ret) ret = wait_reply( req );
--
2.1.1

View File

@ -0,0 +1,27 @@
From 7d9f628d8fa776d60c1f81d88cd1730c65d2f349 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 4 Oct 2014 02:38:27 +0200
Subject: advapi: Trigger write watches before passing userdata pointer to read
syscall.
---
dlls/advapi32/crypt.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/advapi32/crypt.c b/dlls/advapi32/crypt.c
index b2be5e3..50502b8 100644
--- a/dlls/advapi32/crypt.c
+++ b/dlls/advapi32/crypt.c
@@ -2378,7 +2378,8 @@ BOOLEAN WINAPI SystemFunction036(PVOID pbBuffer, ULONG dwLen)
dev_random = open("/dev/urandom", O_RDONLY);
if (dev_random != -1)
{
- if (read(dev_random, pbBuffer, dwLen) == (ssize_t)dwLen)
+ if (!IsBadWritePtr( pbBuffer, dwLen ) &&
+ read(dev_random, pbBuffer, dwLen) == (ssize_t)dwLen)
{
close(dev_random);
return TRUE;
--
2.1.1

View File

@ -0,0 +1,41 @@
From e01c439ea2f8af11a0ebefd23cabf59e0864c142 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Oct 2014 02:48:16 +0200
Subject: ntdll: Fix handling of page fault if a guard page and write watch is
triggered at the same time.
---
dlls/ntdll/virtual.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 4819d2d..f8a5dd3 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1522,11 +1522,6 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err )
{
void *page = ROUND_ADDR( addr, page_mask );
BYTE *vprot = &view->prot[((const char *)page - (const char *)view->base) >> page_shift];
- if (*vprot & VPROT_GUARD)
- {
- VIRTUAL_SetProt( view, page, page_size, *vprot & ~VPROT_GUARD );
- ret = STATUS_GUARD_PAGE_VIOLATION;
- }
if ((err & EXCEPTION_WRITE_FAULT) && (view->protect & VPROT_WRITEWATCH))
{
if (*vprot & VPROT_WRITEWATCH)
@@ -1537,6 +1532,11 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err )
/* ignore fault if page is writable now */
if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS;
}
+ if (*vprot & VPROT_GUARD)
+ {
+ VIRTUAL_SetProt( view, page, page_size, *vprot & ~VPROT_GUARD );
+ ret = STATUS_GUARD_PAGE_VIOLATION;
+ }
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
return ret;
--
2.1.1

View File

@ -0,0 +1,29 @@
From 7bec7a1bbe62894ed24a07fb7cb2af6a1a496210 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Oct 2014 02:49:51 +0200
Subject: ntdll: Avoid race-condition if two threads trigger a write watch at
exactly the same time.
---
dlls/ntdll/virtual.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index f8a5dd3..0864c24 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1522,9 +1522,9 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err )
{
void *page = ROUND_ADDR( addr, page_mask );
BYTE *vprot = &view->prot[((const char *)page - (const char *)view->base) >> page_shift];
- if ((err & EXCEPTION_WRITE_FAULT) && (view->protect & VPROT_WRITEWATCH))
+ if (err & EXCEPTION_WRITE_FAULT)
{
- if (*vprot & VPROT_WRITEWATCH)
+ if ((view->protect & VPROT_WRITEWATCH) && (*vprot & VPROT_WRITEWATCH))
{
*vprot &= ~VPROT_WRITEWATCH;
VIRTUAL_SetProt( view, page, page_size, *vprot );
--
2.1.1

View File

@ -0,0 +1,27 @@
From bcf2dbbc2b5a3551ab2db7ed6d49b1d34c8067d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Oct 2014 02:51:51 +0200
Subject: ntdll: Wait until builtin dlls are unloaded before releasing the
virtual view.
---
dlls/ntdll/loader.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 18ae29c..f0fb1f2 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -2641,8 +2641,8 @@ static void free_modref( WINE_MODREF *wm )
free_tls_slot( &wm->ldr );
RtlReleaseActivationContext( wm->ldr.ActivationContext );
- NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
if (wm->ldr.Flags & LDR_WINE_INTERNAL) wine_dll_unload( wm->ldr.SectionHandle );
+ NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
if (cached_modref == wm) cached_modref = NULL;
RtlFreeUnicodeString( &wm->ldr.FullDllName );
RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
--
2.1.1

View File

@ -0,0 +1,176 @@
From 8237dc994163a63581b9a5414facdab0da897d59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Oct 2014 02:53:22 +0200
Subject: ntdll: Setup a temporary signal handler during process startup to
handle page faults.
---
dlls/ntdll/ntdll_misc.h | 1 +
dlls/ntdll/signal_arm.c | 6 ++++++
dlls/ntdll/signal_arm64.c | 6 ++++++
dlls/ntdll/signal_i386.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/signal_powerpc.c | 6 ++++++
dlls/ntdll/signal_x86_64.c | 6 ++++++
dlls/ntdll/thread.c | 1 +
7 files changed, 73 insertions(+)
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 4370084..53e6b55 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -67,6 +67,7 @@ extern NTSTATUS signal_alloc_thread( TEB **teb ) DECLSPEC_HIDDEN;
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_process(void) DECLSPEC_HIDDEN;
+extern void signal_init_early(void) DECLSPEC_HIDDEN;
extern void version_init( const WCHAR *appname ) DECLSPEC_HIDDEN;
extern void debug_init(void) DECLSPEC_HIDDEN;
extern HANDLE thread_init(void) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index e3ae7bd..1d79b3d 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -930,6 +930,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* __wine_enter_vm86 (NTDLL.@)
diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index 8c8f7af..483bc85 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -791,6 +791,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* __wine_enter_vm86 (NTDLL.@)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 12aa5a4..d24e3bf 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1949,6 +1949,30 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
/**********************************************************************
+ * segv_handler_early
+ *
+ * Handler for SIGSEGV and related errors. Used only during the initialization
+ * of the process to handle virtual faults.
+ */
+static void segv_handler_early( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+ WORD fs, gs;
+ ucontext_t *context = sigcontext;
+ init_handler( sigcontext, &fs, &gs );
+
+ switch(get_trap_code(context))
+ {
+ case TRAP_x86_PAGEFLT: /* Page fault */
+ if (!virtual_handle_fault( siginfo->si_addr, (get_error_code(context) >> 1) & 0x09 ))
+ return;
+ /* fall-through */
+ default:
+ WINE_ERR( "Got unexpected trap %d during process initialization\n", get_trap_code(context) );
+ break;
+ }
+}
+
+/**********************************************************************
* segv_handler
*
* Handler for SIGSEGV and related errors.
@@ -2371,6 +2395,29 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+ struct sigaction sig_act;
+
+ sig_act.sa_mask = server_block_set;
+ sig_act.sa_flags = SA_SIGINFO | SA_RESTART;
+#ifdef SA_ONSTACK
+ sig_act.sa_flags |= SA_ONSTACK;
+#endif
+#ifdef __ANDROID__
+ sig_act.sa_flags |= SA_RESTORER;
+ sig_act.sa_restorer = rt_sigreturn;
+#endif
+ sig_act.sa_sigaction = segv_handler_early;
+ if (sigaction( SIGSEGV, &sig_act, NULL ) == -1)
+ {
+ perror("sigaction");
+ exit(1);
+ }
+}
#ifdef __HAVE_VM86
/**********************************************************************
diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c
index 0fca342..5d1d756 100644
--- a/dlls/ntdll/signal_powerpc.c
+++ b/dlls/ntdll/signal_powerpc.c
@@ -1048,6 +1048,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* __wine_enter_vm86 (NTDLL.@)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 05581c2..22da5d6 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2576,6 +2576,12 @@ void signal_init_process(void)
exit(1);
}
+/**********************************************************************
+ * signal_init_early
+ */
+void signal_init_early(void)
+{
+}
/**********************************************************************
* RtlAddFunctionTable (NTDLL.@)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index c8461b0..a2937c2 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -221,6 +221,7 @@ HANDLE thread_init(void)
static struct debug_info debug_info; /* debug info for initial thread */
virtual_init();
+ signal_init_early();
/* reserve space for shared user data */
--
2.1.1

View File

@ -0,0 +1,74 @@
From 48c067d93de63a0dacbeaf1b962fa614f6015598 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Oct 2014 02:56:08 +0200
Subject: ntdll: Properly handle PAGE_WRITECOPY protection.
---
dlls/kernel32/tests/virtual.c | 12 ++----------
dlls/ntdll/virtual.c | 12 +++++++++++-
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index 0955d30..5b81e38 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -2038,11 +2038,7 @@ todo_wine
SetLastError(0xdeadbeef);
ret = VirtualQuery(base, &info, sizeof(info));
ok(ret, "VirtualQuery failed %d\n", GetLastError());
- /* FIXME: remove the condition below once Wine is fixed */
- if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
- todo_wine ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
- else
- ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
+ ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
}
}
else
@@ -2056,11 +2052,7 @@ todo_wine
SetLastError(0xdeadbeef);
ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
- /* FIXME: remove the condition below once Wine is fixed */
- if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
- todo_wine ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
- else
- ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
+ ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
}
UnmapViewOfFile(base);
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 0864c24..47654f4 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -179,8 +179,13 @@ static int VIRTUAL_GetUnixProt( BYTE vprot )
{
if (vprot & VPROT_READ) prot |= PROT_READ;
if (vprot & VPROT_WRITE) prot |= PROT_WRITE | PROT_READ;
- if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ;
if (vprot & VPROT_EXEC) prot |= PROT_EXEC | PROT_READ;
+#if defined(__i386__)
+ if (vprot & VPROT_WRITECOPY) prot &= ~PROT_WRITE;
+#else
+ /* FIXME: Architecture needs implementation of signal_init_early. */
+ if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ;
+#endif
if (vprot & VPROT_WRITEWATCH) prot &= ~PROT_WRITE;
}
if (!prot) prot = PROT_NONE;
@@ -1529,6 +1534,11 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err )
*vprot &= ~VPROT_WRITEWATCH;
VIRTUAL_SetProt( view, page, page_size, *vprot );
}
+ if (*vprot & VPROT_WRITECOPY)
+ {
+ *vprot = (*vprot & ~VPROT_WRITECOPY) | VPROT_WRITE;
+ VIRTUAL_SetProt( view, page, page_size, *vprot );
+ }
/* ignore fault if page is writable now */
if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS;
}
--
2.1.1

View File

@ -0,0 +1,54 @@
From d333e51c9996681756ceef30322bf20ae907cd68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Oct 2014 03:22:09 +0200
Subject: ntdll: Only enable true WRITECOPY protection when a special
environment variable is set.
---
dlls/ntdll/virtual.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 47654f4..6fad8f7 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -166,6 +166,21 @@ static const char *VIRTUAL_GetProtStr( BYTE prot )
return buffer;
}
+/* This might look like a hack, but it actually isn't - the 'experimental' version
+ * is correct, but it already has revealed a couple of additional Wine bugs, which
+ * were not triggered before, and there are probably some more.
+ * To avoid breaking Wine for everyone, the new correct implementation has to be
+ * manually enabled, until it is tested a bit more. */
+static inline BOOL experimental_WRITECOPY( void )
+{
+ static int enabled = -1;
+ if (enabled == -1)
+ {
+ const char *str = getenv("COMPHOLIO_WRITECOPY");
+ enabled = str && (atoi(str) != 0);
+ }
+ return enabled;
+}
/***********************************************************************
* VIRTUAL_GetUnixProt
@@ -181,7 +196,13 @@ static int VIRTUAL_GetUnixProt( BYTE vprot )
if (vprot & VPROT_WRITE) prot |= PROT_WRITE | PROT_READ;
if (vprot & VPROT_EXEC) prot |= PROT_EXEC | PROT_READ;
#if defined(__i386__)
- if (vprot & VPROT_WRITECOPY) prot &= ~PROT_WRITE;
+ if (vprot & VPROT_WRITECOPY)
+ {
+ if (experimental_WRITECOPY())
+ prot &= ~PROT_WRITE;
+ else
+ prot |= PROT_WRITE | PROT_READ;
+ }
#else
/* FIXME: Architecture needs implementation of signal_init_early. */
if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ;
--
2.1.1

View File

@ -1,4 +1,4 @@
Author: Michael Müller
Subject: Change WRITECOPY memory protection to WRITE on first write.
Revision: 2
Revision: 3
Fixes: [29384] Voobly expects correct handling of WRITECOPY memory protection