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