mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-01-28 22:04:43 -08:00
Added patch to fix issues with execute permissions on pages with guard / write watch flags.
This commit is contained in:
parent
aada22c826
commit
9fb8420891
1
debian/changelog
vendored
1
debian/changelog
vendored
@ -1,6 +1,7 @@
|
||||
wine-compholio (1.7.29) UNRELEASED; urgency=low
|
||||
* Updated DOS Attributes patch to better detect XATTR functions.
|
||||
* Added patch to support IDF_CHECKFIRST in SetupPromptForDisk.
|
||||
* Added patch to fix issues when executing pages with guard page / write watch permissions.
|
||||
* Removed patch to fix issues with drag image in ImageLists (accepted upstream).
|
||||
* Removed patch to set ldr.EntryPoint for main executable (accepted upstream).
|
||||
* Partially removed patches for WRITECOPY memory protection (accepted upstream).
|
||||
|
@ -38,6 +38,7 @@ PATCHLIST := \
|
||||
kernel32-Named_Pipe.ok \
|
||||
kernel32-SystemFileCacheSize.ok \
|
||||
libs-Unicode_Collation.ok \
|
||||
ntdll-ATL_Thunk.ok \
|
||||
ntdll-DOS_Attributes.ok \
|
||||
ntdll-Dynamic_DST.ok \
|
||||
ntdll-Exception.ok \
|
||||
@ -516,6 +517,25 @@ libs-Unicode_Collation.ok:
|
||||
echo '+ { "libs-Unicode_Collation", "Dmitry Timoshkov", "Fix comparison of punctuation characters." },'; \
|
||||
) > libs-Unicode_Collation.ok
|
||||
|
||||
# Patchset ntdll-ATL_Thunk
|
||||
# |
|
||||
# | Included patches:
|
||||
# | * Fix several issues with execute permissions in guard page / write watch handling. [by Sebastian Lackner]
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/kernel32/tests/virtual.c, dlls/ntdll/signal_i386.c, dlls/ntdll/virtual.c, include/winternl.h
|
||||
# |
|
||||
.INTERMEDIATE: ntdll-ATL_Thunk.ok
|
||||
ntdll-ATL_Thunk.ok:
|
||||
$(call APPLY_FILE,ntdll-ATL_Thunk/0001-kernel32-tests-Add-tests-for-DEP-combined-with-guard.patch)
|
||||
$(call APPLY_FILE,ntdll-ATL_Thunk/0002-ntdll-Avoid-recursive-exception-handler-calls-when-h.patch)
|
||||
$(call APPLY_FILE,ntdll-ATL_Thunk/0003-ntdll-Ensure-force_exec_prot-is-also-used-for-views-.patch)
|
||||
$(call APPLY_FILE,ntdll-ATL_Thunk/0004-ntdll-reset_write_watches-shouldn-t-remove-enforced-.patch)
|
||||
$(call APPLY_FILE,ntdll-ATL_Thunk/0005-ntdll-Only-check-for-ATL-thunk-if-DEP-is-not-enabled.patch)
|
||||
@( \
|
||||
echo '+ { "ntdll-ATL_Thunk", "Sebastian Lackner", "Fix several issues with execute permissions in guard page / write watch handling." },'; \
|
||||
) > ntdll-ATL_Thunk.ok
|
||||
|
||||
# Patchset ntdll-DOS_Attributes
|
||||
# |
|
||||
# | Included patches:
|
||||
|
@ -0,0 +1,336 @@
|
||||
From c672ac883d5b2c6f00fb6cff0abd70887dbbcef1 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Wed, 8 Oct 2014 20:54:50 +0200
|
||||
Subject: kernel32/tests: Add tests for DEP combined with guard pages and write
|
||||
watches.
|
||||
|
||||
---
|
||||
dlls/kernel32/tests/virtual.c | 293 ++++++++++++++++++++++++++++++++++++++++++
|
||||
include/winternl.h | 1 +
|
||||
2 files changed, 294 insertions(+)
|
||||
|
||||
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
|
||||
index 0fa2b99..ecb5d2f 100644
|
||||
--- a/dlls/kernel32/tests/virtual.c
|
||||
+++ b/dlls/kernel32/tests/virtual.c
|
||||
@@ -1797,6 +1797,295 @@ static void test_guard_page(void)
|
||||
VirtualFree( base, 0, MEM_FREE );
|
||||
}
|
||||
|
||||
+DWORD num_execute_fault_calls;
|
||||
+
|
||||
+static DWORD execute_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
||||
+ CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
||||
+{
|
||||
+ trace( "exception: %08x flags:%x addr:%p\n",
|
||||
+ rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
|
||||
+
|
||||
+ ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
|
||||
+ ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION || rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION,
|
||||
+ "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION or STATUS_GUARD_PAGE_VIOLATION\n", rec->ExceptionCode );
|
||||
+
|
||||
+ if (rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
|
||||
+ num_guard_page_calls++;
|
||||
+ else if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION)
|
||||
+ {
|
||||
+ DWORD err, old_prot;
|
||||
+ BOOL success;
|
||||
+ ULONG flags;
|
||||
+
|
||||
+ NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags), NULL );
|
||||
+ err = (flags & MEM_EXECUTE_OPTION_DISABLE) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT;
|
||||
+ ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n",
|
||||
+ (DWORD)rec->ExceptionInformation[0], err );
|
||||
+
|
||||
+ success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot );
|
||||
+ ok( success, "VirtualProtect failed %u\n", GetLastError() );
|
||||
+ ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+
|
||||
+ num_execute_fault_calls++;
|
||||
+ }
|
||||
+
|
||||
+ return ExceptionContinueExecution;
|
||||
+}
|
||||
+
|
||||
+static DWORD atl_test_func( DWORD arg )
|
||||
+{
|
||||
+ ok( arg == 0x11223344, "arg is 0x%08x instead of 0x11223344\n", arg );
|
||||
+ return 43;
|
||||
+}
|
||||
+
|
||||
+static void test_data_execution_prevention( ULONG dep_flags )
|
||||
+{
|
||||
+ static const char code_ret[] = {0xB8, 0x2A, 0x00, 0x00, 0x00, 0xC3};
|
||||
+ static const char code_atl[] = {0xC7, 0x44, 0x24, 0x04, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
|
||||
+ EXCEPTION_REGISTRATION_RECORD frame;
|
||||
+ DWORD (*code)(DWORD);
|
||||
+ DWORD ret, size, old_prot;
|
||||
+ ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE;
|
||||
+ void *results[64];
|
||||
+ ULONG_PTR count;
|
||||
+ ULONG pagesize;
|
||||
+ BOOL success;
|
||||
+ char *base;
|
||||
+
|
||||
+ if (!pNtCurrentTeb)
|
||||
+ {
|
||||
+ win_skip( "NtCurrentTeb not supported\n" );
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ trace( "Running DEP tests with ProcessExecuteFlags = %d\n", dep_flags );
|
||||
+
|
||||
+ /* Adjust ProcessExecuteFlags if necessary */
|
||||
+ NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags), NULL );
|
||||
+ if (old_flags != dep_flags)
|
||||
+ {
|
||||
+ ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &dep_flags, sizeof(dep_flags) );
|
||||
+ if (ret == STATUS_INVALID_INFO_CLASS) /* Windows 2000 */
|
||||
+ {
|
||||
+ win_skip( "Skipping DEP tests with ProcessExecuteFlags = %d\n", dep_flags );
|
||||
+ return;
|
||||
+ }
|
||||
+ ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret );
|
||||
+ }
|
||||
+
|
||||
+ size = 0x1000;
|
||||
+ base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
|
||||
+ ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
|
||||
+
|
||||
+ /* write some instructions into the memory, and try to execute it */
|
||||
+ memcpy( base, code_ret, sizeof(code_ret) );
|
||||
+ code = (void *)base;
|
||||
+
|
||||
+ frame.Handler = execute_fault_handler;
|
||||
+ frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+ else
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
+
|
||||
+ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
|
||||
+ ok( success, "VirtualProtect failed %u\n", GetLastError() );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+ else
|
||||
+ ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+
|
||||
+ /* the same, but with PAGE_GUARD set */
|
||||
+ frame.Handler = execute_fault_handler;
|
||||
+ frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+ else
|
||||
+ todo_wine
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
+
|
||||
+ /* special case, test with ATL thunk */
|
||||
+ memcpy( base, code_atl, sizeof(code_atl) );
|
||||
+ *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
|
||||
+
|
||||
+ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
|
||||
+ ok( success, "VirtualProtect failed %u\n", GetLastError() );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+ else
|
||||
+ todo_wine
|
||||
+ ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+
|
||||
+ frame.Handler = execute_fault_handler;
|
||||
+ frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ todo_wine
|
||||
+ ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+ else
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
+
|
||||
+ VirtualFree( base, 0, MEM_FREE );
|
||||
+
|
||||
+ /* same as above, but using memory with a write watch */
|
||||
+ base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE );
|
||||
+ if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
|
||||
+ {
|
||||
+ win_skip( "MEM_WRITE_WATCH not supported\n" );
|
||||
+ goto out;
|
||||
+ }
|
||||
+ ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
|
||||
+
|
||||
+ count = 64;
|
||||
+ ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
|
||||
+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
+ ok( count == 0, "wrong count %lu\n", count );
|
||||
+
|
||||
+ /* write some instructions into the memory, and try to execute it */
|
||||
+ memcpy( base, code_ret, sizeof(code_ret) );
|
||||
+ code = (void *)base;
|
||||
+
|
||||
+ count = 64;
|
||||
+ ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
+ ok( count == 1, "wrong count %lu\n", count );
|
||||
+ ok( results[0] == base, "wrong result %p\n", results[0] );
|
||||
+
|
||||
+ frame.Handler = execute_fault_handler;
|
||||
+ frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+ else
|
||||
+ todo_wine
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
+
|
||||
+ count = 64;
|
||||
+ ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
+ ok( count == 0, "wrong count %lu\n", count );
|
||||
+
|
||||
+ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
|
||||
+ ok( success, "VirtualProtect failed %u\n", GetLastError() );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+ else
|
||||
+ todo_wine
|
||||
+ ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+
|
||||
+ /* the same, but with PAGE_GUARD set */
|
||||
+ frame.Handler = execute_fault_handler;
|
||||
+ frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+ else
|
||||
+ todo_wine
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
+
|
||||
+ count = 64;
|
||||
+ ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
+ ok( count == 0 || broken(count == 1) /* < Windows 8 */, "wrong count %lu\n", count );
|
||||
+
|
||||
+ /* special case, test with ATL thunk */
|
||||
+ memcpy( base, code_atl, sizeof(code_atl) );
|
||||
+ *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
|
||||
+
|
||||
+ count = 64;
|
||||
+ ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
+ ok( count == 1, "wrong count %lu\n", count );
|
||||
+ ok( results[0] == base, "wrong result %p\n", results[0] );
|
||||
+
|
||||
+ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
|
||||
+ ok( success, "VirtualProtect failed %u\n", GetLastError() );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+ else
|
||||
+ todo_wine
|
||||
+ ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
+
|
||||
+ frame.Handler = execute_fault_handler;
|
||||
+ frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
+ todo_wine
|
||||
+ ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+ else
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ num_guard_page_calls = num_execute_fault_calls = 0;
|
||||
+ ret = code( 0xdeadbeef );
|
||||
+ ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
|
||||
+ ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
+ ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
+
|
||||
+ count = 64;
|
||||
+ ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
|
||||
+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
|
||||
+ ok( count == 0 || broken(count == 1) /* < Windows 8 */, "wrong count %lu\n", count );
|
||||
+
|
||||
+ pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
+
|
||||
+ VirtualFree( base, 0, MEM_FREE );
|
||||
+
|
||||
+out:
|
||||
+ if (old_flags != dep_flags)
|
||||
+ {
|
||||
+ ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags) );
|
||||
+ ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret );
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#endif /* __i386__ */
|
||||
|
||||
static void test_VirtualProtect(void)
|
||||
@@ -2859,5 +3148,9 @@ START_TEST(virtual)
|
||||
test_write_watch();
|
||||
#ifdef __i386__
|
||||
test_guard_page();
|
||||
+ test_data_execution_prevention( MEM_EXECUTE_OPTION_ENABLE );
|
||||
+ test_data_execution_prevention( MEM_EXECUTE_OPTION_ENABLE | MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION );
|
||||
+ test_data_execution_prevention( MEM_EXECUTE_OPTION_DISABLE );
|
||||
+ test_data_execution_prevention( MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION );
|
||||
#endif
|
||||
}
|
||||
diff --git a/include/winternl.h b/include/winternl.h
|
||||
index 95951e2..7f9a85d 100644
|
||||
--- a/include/winternl.h
|
||||
+++ b/include/winternl.h
|
||||
@@ -728,6 +728,7 @@ typedef enum _PROCESSINFOCLASS {
|
||||
|
||||
#define MEM_EXECUTE_OPTION_DISABLE 0x01
|
||||
#define MEM_EXECUTE_OPTION_ENABLE 0x02
|
||||
+#define MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION 0x04
|
||||
#define MEM_EXECUTE_OPTION_PERMANENT 0x08
|
||||
|
||||
typedef enum _SECTION_INHERIT {
|
||||
--
|
||||
2.1.2
|
||||
|
@ -0,0 +1,68 @@
|
||||
From 5dc9f7a909b8d0e7bee4be1c0b846a21b7e78240 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Wed, 8 Oct 2014 21:11:55 +0200
|
||||
Subject: ntdll: Avoid recursive exception handler calls when handling guard
|
||||
pages.
|
||||
|
||||
The ATL check leads to problems when a page is protected with guard page protection.
|
||||
raise_segv_exception is called with EXCEPTION_EXECUTE_FAULT. The ATL check tries to
|
||||
read the memory, and triggers another exception handler. This time the virtual_handle_fault
|
||||
check is executed, and removes the guard page protection. Afterwards, when the ATL
|
||||
check returns, the exception is _not_ catched by virtual_handle_fault, but instead
|
||||
passed to the application.
|
||||
---
|
||||
dlls/kernel32/tests/virtual.c | 2 --
|
||||
dlls/ntdll/signal_i386.c | 10 ++++++----
|
||||
2 files changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
|
||||
index ecb5d2f..90a5578 100644
|
||||
--- a/dlls/kernel32/tests/virtual.c
|
||||
+++ b/dlls/kernel32/tests/virtual.c
|
||||
@@ -1915,7 +1915,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
else
|
||||
- todo_wine
|
||||
ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
|
||||
pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
@@ -1929,7 +1928,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
else
|
||||
- todo_wine
|
||||
ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
|
||||
frame.Handler = execute_fault_handler;
|
||||
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
|
||||
index 12aa5a4..b9b45a8 100644
|
||||
--- a/dlls/ntdll/signal_i386.c
|
||||
+++ b/dlls/ntdll/signal_i386.c
|
||||
@@ -1821,17 +1821,19 @@ static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
if (rec->NumberParameters == 2)
|
||||
{
|
||||
- if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT && check_atl_thunk( rec, context ))
|
||||
- goto done;
|
||||
if (rec->ExceptionInformation[1] == 0xffffffff && check_invalid_gs( context ))
|
||||
goto done;
|
||||
if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
|
||||
rec->ExceptionInformation[0] )))
|
||||
goto done;
|
||||
- /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
|
||||
- if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
|
||||
+ if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
|
||||
+ rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
|
||||
{
|
||||
ULONG flags;
|
||||
+ if (check_atl_thunk( rec, context ))
|
||||
+ goto done;
|
||||
+
|
||||
+ /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
|
||||
NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
|
||||
&flags, sizeof(flags), NULL );
|
||||
if (!(flags & MEM_EXECUTE_OPTION_DISABLE))
|
||||
--
|
||||
2.1.2
|
||||
|
@ -0,0 +1,100 @@
|
||||
From 94360ac47e9300f85ab0f63c49ba8044107ac1c1 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Wed, 8 Oct 2014 21:26:28 +0200
|
||||
Subject: ntdll: Ensure force_exec_prot is also used for views with write watch
|
||||
permissions.
|
||||
|
||||
---
|
||||
dlls/kernel32/tests/virtual.c | 2 --
|
||||
dlls/ntdll/virtual.c | 36 +++++++++++++++++++++++-------------
|
||||
2 files changed, 23 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
|
||||
index 90a5578..a233b37 100644
|
||||
--- a/dlls/kernel32/tests/virtual.c
|
||||
+++ b/dlls/kernel32/tests/virtual.c
|
||||
@@ -2019,7 +2019,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
else
|
||||
- todo_wine
|
||||
ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
|
||||
pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
@@ -2044,7 +2043,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
else
|
||||
- todo_wine
|
||||
ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
|
||||
frame.Handler = execute_fault_handler;
|
||||
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
|
||||
index f8a5dd3..3c9a4b5 100644
|
||||
--- a/dlls/ntdll/virtual.c
|
||||
+++ b/dlls/ntdll/virtual.c
|
||||
@@ -591,6 +591,25 @@ static NTSTATUS get_vprot_flags( DWORD protect, unsigned int *vprot, BOOL image
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
+ * mprotect_exec
|
||||
+ *
|
||||
+ * Wrapper for mprotect, adds PROT_EXEC if forced by force_exec_prot
|
||||
+ */
|
||||
+static inline int mprotect_exec( void *base, size_t size, int unix_prot, unsigned int view_protect )
|
||||
+{
|
||||
+ if (force_exec_prot && !(view_protect & VPROT_NOEXEC) &&
|
||||
+ (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 )) return 0;
|
||||
+ /* exec + write may legitimately fail, in that case fall back to write only */
|
||||
+ if (!(unix_prot & PROT_WRITE)) return -1;
|
||||
+ }
|
||||
+
|
||||
+ return mprotect( base, size, unix_prot );
|
||||
+}
|
||||
+
|
||||
+/***********************************************************************
|
||||
* VIRTUAL_SetProt
|
||||
*
|
||||
* Change the protection of a range of pages.
|
||||
@@ -624,12 +643,12 @@ static BOOL VIRTUAL_SetProt( struct file_view *view, /* [in] Pointer to view */
|
||||
p[i] = vprot | (p[i] & VPROT_WRITEWATCH);
|
||||
prot = VIRTUAL_GetUnixProt( p[i] );
|
||||
if (prot == unix_prot) continue;
|
||||
- mprotect( addr, count << page_shift, unix_prot );
|
||||
+ mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
|
||||
addr += count << page_shift;
|
||||
unix_prot = prot;
|
||||
count = 0;
|
||||
}
|
||||
- if (count) mprotect( addr, count << page_shift, unix_prot );
|
||||
+ if (count) mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
|
||||
VIRTUAL_DEBUG_DUMP_VIEW( view );
|
||||
return TRUE;
|
||||
}
|
||||
@@ -646,18 +665,9 @@ static BOOL VIRTUAL_SetProt( struct file_view *view, /* [in] Pointer to view */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- if (force_exec_prot && !(view->protect & VPROT_NOEXEC) &&
|
||||
- (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 */
|
||||
+ if (mprotect_exec( base, size, unix_prot, view->protect )) /* FIXME: last error */
|
||||
+ return FALSE;
|
||||
|
||||
-done:
|
||||
memset( p, vprot, size >> page_shift );
|
||||
VIRTUAL_DEBUG_DUMP_VIEW( view );
|
||||
return TRUE;
|
||||
--
|
||||
2.1.2
|
||||
|
@ -0,0 +1,53 @@
|
||||
From db098e8367cb2f01a7f5a4d6309e0ea476821e60 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Wed, 8 Oct 2014 21:28:25 +0200
|
||||
Subject: ntdll: reset_write_watches shouldn't remove enforced exec
|
||||
permissions.
|
||||
|
||||
---
|
||||
dlls/kernel32/tests/virtual.c | 2 --
|
||||
dlls/ntdll/virtual.c | 4 ++--
|
||||
2 files changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
|
||||
index a233b37..f236edb 100644
|
||||
--- a/dlls/kernel32/tests/virtual.c
|
||||
+++ b/dlls/kernel32/tests/virtual.c
|
||||
@@ -1989,7 +1989,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
else
|
||||
- todo_wine
|
||||
ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
|
||||
pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
||||
@@ -2004,7 +2003,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
ok( old_prot == PAGE_EXECUTE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
else
|
||||
- todo_wine
|
||||
ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
|
||||
|
||||
/* the same, but with PAGE_GUARD set */
|
||||
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
|
||||
index 3c9a4b5..d2bb152 100644
|
||||
--- a/dlls/ntdll/virtual.c
|
||||
+++ b/dlls/ntdll/virtual.c
|
||||
@@ -693,12 +693,12 @@ static void reset_write_watches( struct file_view *view, void *base, SIZE_T size
|
||||
p[i] |= VPROT_WRITEWATCH;
|
||||
prot = VIRTUAL_GetUnixProt( p[i] );
|
||||
if (prot == unix_prot) continue;
|
||||
- mprotect( addr, count << page_shift, unix_prot );
|
||||
+ mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
|
||||
addr += count << page_shift;
|
||||
unix_prot = prot;
|
||||
count = 0;
|
||||
}
|
||||
- if (count) mprotect( addr, count << page_shift, unix_prot );
|
||||
+ if (count) mprotect_exec( addr, count << page_shift, unix_prot, view->protect );
|
||||
}
|
||||
|
||||
|
||||
--
|
||||
2.1.2
|
||||
|
@ -0,0 +1,56 @@
|
||||
From 7df7b751e99689d72cf41095df1d697ccc41a1ab Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Wed, 8 Oct 2014 21:32:46 +0200
|
||||
Subject: ntdll: Only check for ATL thunk if DEP is not enabled.
|
||||
|
||||
---
|
||||
dlls/kernel32/tests/virtual.c | 2 --
|
||||
dlls/ntdll/signal_i386.c | 8 ++++----
|
||||
2 files changed, 4 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
|
||||
index f236edb..1bed9bc 100644
|
||||
--- a/dlls/kernel32/tests/virtual.c
|
||||
+++ b/dlls/kernel32/tests/virtual.c
|
||||
@@ -1939,7 +1939,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
|
||||
ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
- todo_wine
|
||||
ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
else
|
||||
ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
@@ -2052,7 +2051,6 @@ static void test_data_execution_prevention( ULONG dep_flags )
|
||||
ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
|
||||
ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
|
||||
if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
|
||||
- todo_wine
|
||||
ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
else
|
||||
ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
|
||||
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
|
||||
index b9b45a8..f854dec 100644
|
||||
--- a/dlls/ntdll/signal_i386.c
|
||||
+++ b/dlls/ntdll/signal_i386.c
|
||||
@@ -1830,14 +1830,14 @@ static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context
|
||||
rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
|
||||
{
|
||||
ULONG flags;
|
||||
- if (check_atl_thunk( rec, context ))
|
||||
- goto done;
|
||||
-
|
||||
- /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
|
||||
NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
|
||||
&flags, sizeof(flags), NULL );
|
||||
if (!(flags & MEM_EXECUTE_OPTION_DISABLE))
|
||||
+ {
|
||||
+ if (check_atl_thunk( rec, context ))
|
||||
+ goto done;
|
||||
rec->ExceptionInformation[0] = EXCEPTION_READ_FAULT;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
break;
|
||||
--
|
||||
2.1.2
|
||||
|
3
patches/ntdll-ATL_Thunk/definition
Normal file
3
patches/ntdll-ATL_Thunk/definition
Normal file
@ -0,0 +1,3 @@
|
||||
Author: Sebastian Lackner
|
||||
Subject: Fix several issues with execute permissions in guard page / write watch handling.
|
||||
Revision: 1
|
Loading…
x
Reference in New Issue
Block a user