Alexandre Julliard : ntdll: Make x86_64 syscall thunks position independent.
Alexandre Julliard
julliard at winehq.org
Wed Nov 25 15:58:54 CST 2020
Module: wine
Branch: master
Commit: 043489456c1f633f86f8dd1fde6b32c48c90c6f4
URL: https://source.winehq.org/git/wine.git/?a=commit;h=043489456c1f633f86f8dd1fde6b32c48c90c6f4
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed Nov 25 20:19:43 2020 +0100
ntdll: Make x86_64 syscall thunks position independent.
Based on a patch by Paul Gofman.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/tests/virtual.c | 111 +++++++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/unix/virtual.c | 6 +++
tools/winebuild/import.c | 4 +-
3 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c
index 9c2cf824018..546a7d83bbd 100644
--- a/dlls/ntdll/tests/virtual.c
+++ b/dlls/ntdll/tests/virtual.c
@@ -643,6 +643,116 @@ static void test_user_shared_data(void)
}
}
+static void perform_relocations( void *module, INT_PTR delta )
+{
+ IMAGE_NT_HEADERS *nt;
+ IMAGE_BASE_RELOCATION *rel, *end;
+ const IMAGE_DATA_DIRECTORY *relocs;
+ const IMAGE_SECTION_HEADER *sec;
+ ULONG protect_old[96], i;
+
+ nt = RtlImageNtHeader( module );
+ relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ if (!relocs->VirtualAddress || !relocs->Size) return;
+ sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
+ nt->FileHeader.SizeOfOptionalHeader);
+ for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+ {
+ void *addr = (char *)module + sec[i].VirtualAddress;
+ SIZE_T size = sec[i].SizeOfRawData;
+ NtProtectVirtualMemory( NtCurrentProcess(), &addr,
+ &size, PAGE_READWRITE, &protect_old[i] );
+ }
+ rel = (IMAGE_BASE_RELOCATION *)((char *)module + relocs->VirtualAddress);
+ end = (IMAGE_BASE_RELOCATION *)((char *)rel + relocs->Size);
+ while (rel && rel < end - 1 && rel->SizeOfBlock)
+ rel = LdrProcessRelocationBlock( (char *)module + rel->VirtualAddress,
+ (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
+ (USHORT *)(rel + 1), delta );
+ for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+ {
+ void *addr = (char *)module + sec[i].VirtualAddress;
+ SIZE_T size = sec[i].SizeOfRawData;
+ NtProtectVirtualMemory( NtCurrentProcess(), &addr,
+ &size, protect_old[i], &protect_old[i] );
+ }
+}
+
+
+static void test_syscalls(void)
+{
+ HMODULE module = GetModuleHandleW( L"ntdll.dll" );
+ HANDLE handle;
+ NTSTATUS status;
+ NTSTATUS (WINAPI *pNtClose)(HANDLE);
+ WCHAR path[MAX_PATH];
+ HANDLE file, mapping;
+ INT_PTR delta;
+ void *ptr;
+
+ /* initial image */
+ pNtClose = (void *)GetProcAddress( module, "NtClose" );
+ handle = CreateEventW( NULL, FALSE, FALSE, NULL );
+ ok( handle != 0, "CreateEventWfailed %u\n", GetLastError() );
+ status = pNtClose( handle );
+ ok( !status, "NtClose failed %x\n", status );
+ status = pNtClose( handle );
+ ok( status == STATUS_INVALID_HANDLE, "NtClose failed %x\n", status );
+
+ /* syscall thunk copy */
+ ptr = VirtualAlloc( NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+ ok( ptr != NULL, "VirtualAlloc failed\n" );
+ memcpy( ptr, pNtClose, 32 );
+ pNtClose = ptr;
+ handle = CreateEventW( NULL, FALSE, FALSE, NULL );
+ ok( handle != 0, "CreateEventWfailed %u\n", GetLastError() );
+ status = pNtClose( handle );
+ ok( !status, "NtClose failed %x\n", status );
+ status = pNtClose( handle );
+ ok( status == STATUS_INVALID_HANDLE, "NtClose failed %x\n", status );
+ VirtualFree( ptr, 0, MEM_FREE );
+
+ /* new mapping */
+ GetModuleFileNameW( module, path, MAX_PATH );
+ file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
+ ok( file != INVALID_HANDLE_VALUE, "can't open %s: %u\n", wine_dbgstr_w(path), GetLastError() );
+ mapping = CreateFileMappingW( file, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL );
+ ok( mapping != NULL, "CreateFileMappingW failed err %u\n", GetLastError() );
+ ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
+ ok( ptr != NULL, "MapViewOfFile failed err %u\n", GetLastError() );
+ CloseHandle( mapping );
+ CloseHandle( file );
+ delta = (char *)ptr - (char *)module;
+
+ if (memcmp( ptr, module, 0x1000 ))
+ {
+ skip( "modules are not identical (non-PE build?)\n" );
+ UnmapViewOfFile( ptr );
+ return;
+ }
+ perform_relocations( ptr, delta );
+ pNtClose = (void *)GetProcAddress( module, "NtClose" );
+ if (!memcmp( pNtClose, (char *)pNtClose + delta, 32 ))
+ {
+ pNtClose = (void *)((char *)pNtClose + delta);
+ handle = CreateEventW( NULL, FALSE, FALSE, NULL );
+ ok( handle != 0, "CreateEventWfailed %u\n", GetLastError() );
+ status = pNtClose( handle );
+ ok( !status, "NtClose failed %x\n", status );
+ status = pNtClose( handle );
+ ok( status == STATUS_INVALID_HANDLE, "NtClose failed %x\n", status );
+ }
+ else
+ {
+#ifdef __x86_64__
+ ok( 0, "syscall thunk relocated\n" );
+#else
+ skip( "syscall thunk relocated\n" );
+#endif
+ }
+ UnmapViewOfFile( ptr );
+}
+
START_TEST(virtual)
{
HMODULE mod;
@@ -678,4 +788,5 @@ START_TEST(virtual)
test_RtlCreateUserStack();
test_NtMapViewOfSection();
test_user_shared_data();
+ test_syscalls();
}
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 853eb0469b9..eaaf7242883 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -2582,6 +2582,12 @@ TEB *virtual_alloc_first_teb(void)
exit(1);
}
+#ifdef __x86_64__ /* sneak in a syscall dispatcher pointer at a fixed address (7ffe1000) */
+ ptr = (char *)user_shared_data + page_size;
+ anon_mmap_fixed( ptr, page_size, PROT_READ | PROT_WRITE, 0 );
+ *(void **)ptr = __wine_syscall_dispatcher;
+#endif
+
NtAllocateVirtualMemory( NtCurrentProcess(), &teb_block, 0, &total,
MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
teb_block_pos = 30;
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 62d9844e367..53d4fb2869b 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -1727,8 +1727,8 @@ void output_syscalls( DLLSPEC *spec )
output( "\t.byte 0xc3\n" ); /* ret */
if (target_platform == PLATFORM_WINDOWS)
{
- output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(__wine_syscall_dispatcher) */
- output( "\t.long __wine_syscall_dispatcher\n" );
+ output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
+ output( "\t.long 0x7ffe1000\n" );
}
else
{
More information about the wine-cvs
mailing list