From 8c7754a1da9f43cf15057a8467c0b76c9da2ce40 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 22 Nov 2014 05:49:30 +0100 Subject: ntdll: Fix issues with write watches when using Exagear. --- dlls/ntdll/virtual.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 1a8e4a4..4140323 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1558,6 +1558,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]; +#ifdef EXAGEAR_COMPAT + /* Exagear doesn't correctly set err, so always check for write watches, and + * retry after removing the VPROT_WRITEWATCH or VPROT_WRITECOPY flag. In + * contrary to the general implementation below this is not completely race- + * condition safe. When multiple threads trigger the write watch at the same + * time only the first thread will properly continue the execution, the rest + * will crash. */ + if ((view->protect & VPROT_WRITEWATCH) && (*vprot & VPROT_WRITEWATCH)) + { + *vprot &= ~VPROT_WRITEWATCH; + VIRTUAL_SetProt( view, page, page_size, *vprot ); + if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS; + } + if (*vprot & VPROT_WRITECOPY) + { + *vprot = (*vprot & ~VPROT_WRITECOPY) | VPROT_WRITE; + VIRTUAL_SetProt( view, page, page_size, *vprot ); + if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS; + } +#else if (err & EXCEPTION_WRITE_FAULT) { if ((view->protect & VPROT_WRITEWATCH) && (*vprot & VPROT_WRITEWATCH)) @@ -1573,6 +1593,7 @@ NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err ) /* ignore fault if page is writable now */ if (VIRTUAL_GetUnixProt( *vprot ) & PROT_WRITE) ret = STATUS_SUCCESS; } +#endif if (*vprot & VPROT_GUARD) { VIRTUAL_SetProt( view, page, page_size, *vprot & ~VPROT_GUARD ); -- 2.1.3