wine-staging/patches/ntdll-WRITECOPY/0005-ntdll-Track-if-a-WRITECOPY-page-has-been-modified.patch

98 lines
4.0 KiB
Diff
Raw Normal View History

From c38118527458007162f8cbe38bec0dd02b9de6e7 Mon Sep 17 00:00:00 2001
From: Andrew Wesie <awesie@gmail.com>
Date: Fri, 24 Apr 2020 14:55:14 -0500
Subject: [PATCH] ntdll: Track if a WRITECOPY page has been modified.
Once a WRITECOPY page is modified, it should be mapped as if it is a normal
read-write page.
Signed-off-by: Andrew Wesie <awesie@gmail.com>
---
dlls/ntdll/virtual.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 3533a087d88..75219ae2376 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -85,6 +85,7 @@ struct file_view
#define VPROT_GUARD 0x10
#define VPROT_COMMITTED 0x20
#define VPROT_WRITEWATCH 0x40
+#define VPROT_WRITTEN 0x80
/* per-mapping protection flags */
#define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */
@@ -353,7 +354,7 @@ static int VIRTUAL_GetUnixProt( BYTE vprot )
#if defined(__i386__)
if (vprot & VPROT_WRITECOPY)
{
- if (experimental_WRITECOPY())
+ if (experimental_WRITECOPY() && !(vprot & VPROT_WRITTEN))
prot = (prot & ~PROT_WRITE) | PROT_READ;
else
prot |= PROT_WRITE | PROT_READ;
@@ -925,7 +926,11 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz
*/
static DWORD VIRTUAL_GetWin32Prot( BYTE vprot, unsigned int map_prot )
{
- DWORD ret = VIRTUAL_Win32Flags[vprot & 0x0f];
+ DWORD ret;
+
+ if ((vprot & VPROT_WRITECOPY) && (vprot & VPROT_WRITTEN))
+ vprot = (vprot & ~VPROT_WRITECOPY) | VPROT_WRITE;
+ ret = VIRTUAL_Win32Flags[vprot & 0x0f];
if (vprot & VPROT_GUARD) ret |= PAGE_GUARD;
if (map_prot & SEC_NOCACHE) ret |= PAGE_NOCACHE;
return ret;
@@ -1049,7 +1054,7 @@ 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 */
- set_page_vprot_bits( base, size, vprot & ~VPROT_WRITEWATCH, ~vprot & ~VPROT_WRITEWATCH );
+ set_page_vprot_bits( base, size, vprot & ~VPROT_WRITEWATCH, ~vprot & ~(VPROT_WRITEWATCH|VPROT_WRITTEN) );
mprotect_range( base, size, 0, 0 );
return TRUE;
}
@@ -1065,10 +1070,18 @@ static BOOL VIRTUAL_SetProt( struct file_view *view, /* [in] Pointer to view */
return TRUE;
}
+ /* check that we can map this memory with PROT_WRITE since we cannot fail later */
+ if (vprot & VPROT_WRITECOPY)
+ unix_prot |= PROT_WRITE;
+
if (mprotect_exec( base, size, unix_prot )) /* FIXME: last error */
return FALSE;
- set_page_vprot( base, size, vprot );
+ /* each page may need different protections depending on writecopy */
+ set_page_vprot_bits( base, size, vprot, ~vprot & ~VPROT_WRITTEN );
+ if (vprot & VPROT_WRITECOPY)
+ mprotect_range( base, size, 0, 0 );
+
return TRUE;
}
@@ -2368,7 +2381,7 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack )
}
if (vprot & VPROT_WRITECOPY)
{
- set_page_vprot_bits( page, page_size, VPROT_WRITE, VPROT_WRITECOPY );
+ set_page_vprot_bits( page, page_size, VPROT_WRITE | VPROT_WRITTEN, VPROT_WRITECOPY );
mprotect_range( page, page_size, 0, 0 );
}
/* ignore fault if page is writable now */
@@ -3272,7 +3285,7 @@ static NTSTATUS get_basic_memory_info( HANDLE process, LPCVOID addr,
else if (view->protect & (SEC_FILE | SEC_RESERVE | SEC_COMMIT)) info->Type = MEM_MAPPED;
else info->Type = MEM_PRIVATE;
for (ptr = base; ptr < base + range_size; ptr += page_size)
- if ((get_page_vprot( ptr ) ^ vprot) & ~VPROT_WRITEWATCH) break;
+ if ((get_page_vprot( ptr ) ^ vprot) & ~(VPROT_WRITEWATCH|VPROT_WRITTEN)) break;
info->RegionSize = ptr - base;
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
--
2.26.2