From 51b447a55ff069802fd4031bceb944017ac7a3f9 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Thu, 28 Apr 2016 17:13:03 +0200 Subject: [PATCH] ntdll-NtSetLdtEntries: Update patchset and add actual implementation of NtSetLdtEntries. --- ...0002-ntdll-Implement-NtSetLdtEntries.patch | 170 ++++++++++++++++++ ...Allow-to-modify-reserved-LDT-entries.patch | 68 +++++++ ...-Export-NtSetLdtEntries-only-on-i386.patch | 67 +++++++ patches/patchinstall.sh | 9 +- 4 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 patches/ntdll-NtSetLdtEntries/0002-ntdll-Implement-NtSetLdtEntries.patch create mode 100644 patches/ntdll-NtSetLdtEntries/0003-libs-wine-Allow-to-modify-reserved-LDT-entries.patch create mode 100644 patches/ntdll-NtSetLdtEntries/0004-ntdll-Export-NtSetLdtEntries-only-on-i386.patch diff --git a/patches/ntdll-NtSetLdtEntries/0002-ntdll-Implement-NtSetLdtEntries.patch b/patches/ntdll-NtSetLdtEntries/0002-ntdll-Implement-NtSetLdtEntries.patch new file mode 100644 index 00000000..62029c87 --- /dev/null +++ b/patches/ntdll-NtSetLdtEntries/0002-ntdll-Implement-NtSetLdtEntries.patch @@ -0,0 +1,170 @@ +From aadd7b2c0ca9bf60d64c3ed4e0722de3899b8c13 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Thu, 28 Apr 2016 18:14:36 +0800 +Subject: ntdll: Implement NtSetLdtEntries. + +--- + dlls/kernel32/tests/thread.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/nt.c | 28 +++++++++++++++- + 2 files changed, 106 insertions(+), 1 deletion(-) + +diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c +index e0de3f9..981e3c4 100644 +--- a/dlls/kernel32/tests/thread.c ++++ b/dlls/kernel32/tests/thread.c +@@ -102,6 +102,7 @@ static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID + static BOOL (WINAPI *pGetThreadGroupAffinity)(HANDLE,GROUP_AFFINITY*); + static BOOL (WINAPI *pSetThreadGroupAffinity)(HANDLE,const GROUP_AFFINITY*,GROUP_AFFINITY*); + static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG); ++static NTSTATUS (WINAPI *pNtSetLdtEntries)(ULONG,ULONG,ULONG,ULONG,ULONG,ULONG); + + static HANDLE create_target_process(const char *arg) + { +@@ -1100,6 +1101,82 @@ static void test_SetThreadContext(void) + CloseHandle( thread ); + } + ++static void test_NtSetLdtEntries(void) ++{ ++ THREAD_DESCRIPTOR_INFORMATION tdi; ++ LDT_ENTRY ds_entry; ++ CONTEXT ctx; ++ DWORD ret; ++ union ++ { ++ LDT_ENTRY entry; ++ DWORD dw[2]; ++ } sel; ++ ++ if (!pNtSetLdtEntries) ++ { ++ win_skip("NtSetLdtEntries is not available on this platform\n"); ++ return; ++ } ++ ++ if (pNtSetLdtEntries(0, 0, 0, 0, 0, 0) == STATUS_NOT_IMPLEMENTED) /* WoW64 */ ++ { ++ win_skip("NtSetLdtEntries is not implemented on this platform\n"); ++ return; ++ } ++ ++ ret = pNtSetLdtEntries(0, 0, 0, 0, 0, 0); ++ ok(!ret, "NtSetLdtEntries failed: %08x\n", ret); ++ ++ ctx.ContextFlags = CONTEXT_SEGMENTS; ++ ret = GetThreadContext(GetCurrentThread(), &ctx); ++ ok(ret, "GetThreadContext failed\n"); ++ ++ tdi.Selector = ctx.SegDs; ++ ret = pNtQueryInformationThread(GetCurrentThread(), 6 /*ThreadDescriptorTableEntry*/, &tdi, sizeof(tdi), &ret); ++ ok(!ret, "NtQueryInformationThread failed: %08x\n", ret); ++ ds_entry = tdi.Entry; ++ ++ tdi.Selector = 0x000f; ++ ret = pNtQueryInformationThread(GetCurrentThread(), 6 /*ThreadDescriptorTableEntry*/, &tdi, sizeof(tdi), &ret); ++ ok(ret == STATUS_ACCESS_VIOLATION, "got %08x\n", ret); ++ ++ tdi.Selector = 0x001f; ++ ret = pNtQueryInformationThread(GetCurrentThread(), 6 /*ThreadDescriptorTableEntry*/, &tdi, sizeof(tdi), &ret); ++ ok(ret == STATUS_ACCESS_VIOLATION, "NtQueryInformationThread returned %08x\n", ret); ++ ++ ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry); ++ ok(!ret, "GetThreadSelectorEntry should fail\n"); ++ ++ ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry); ++ ok(!ret, "GetThreadSelectorEntry should fail\n"); ++ ++ memset(&sel.entry, 0x9a, sizeof(sel.entry)); ++ ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &sel.entry); ++ ok(ret, "GetThreadSelectorEntry failed\n"); ++ ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); ++ ++ ret = pNtSetLdtEntries(0x000f, sel.dw[0], sel.dw[1], 0x001f, sel.dw[0], sel.dw[1]); ++ ok(!ret || broken(ret == STATUS_INVALID_LDT_DESCRIPTOR) /*XP*/, "NtSetLdtEntries failed: %08x\n", ret); ++ ++ if (!ret) ++ { ++ memset(&sel.entry, 0x9a, sizeof(sel.entry)); ++ ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry); ++ todo_wine ++ ok(ret, "GetThreadSelectorEntry failed\n"); ++ todo_wine ++ ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); ++ ++ memset(&sel.entry, 0x9a, sizeof(sel.entry)); ++ ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry); ++ todo_wine ++ ok(ret, "GetThreadSelectorEntry failed\n"); ++ todo_wine ++ ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); ++ } ++} ++ + #endif /* __i386__ */ + + static HANDLE finish_event; +@@ -1913,6 +1990,7 @@ static void init_funcs(void) + X(NtQueryInformationThread); + X(RtlGetThreadErrorMode); + X(NtSetInformationThread); ++ X(NtSetLdtEntries); + } + #undef X + } +@@ -1965,6 +2043,7 @@ START_TEST(thread) + test_GetThreadExitCode(); + #ifdef __i386__ + test_SetThreadContext(); ++ test_NtSetLdtEntries(); + #endif + test_QueueUserWorkItem(); + test_RegisterWaitForSingleObject(); +diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c +index 3f5ae2c..fbea627 100644 +--- a/dlls/ntdll/nt.c ++++ b/dlls/ntdll/nt.c +@@ -56,6 +56,7 @@ + #include "winternl.h" + #include "ntdll_misc.h" + #include "wine/server.h" ++#include "wine/library.h" + #include "ddk/wdm.h" + + #ifdef __APPLE__ +@@ -2790,7 +2791,32 @@ NTSTATUS WINAPI NtSystemDebugControl(SYSDBG_COMMAND command, PVOID inbuffer, ULO + NTSTATUS WINAPI NtSetLdtEntries(ULONG selector1, ULONG entry1_low, ULONG entry1_high, + ULONG selector2, ULONG entry2_low, ULONG entry2_high) + { +- FIXME("(%u, %u, %u, %u, %u, %u): stub\n", selector1, entry1_low, entry1_high, selector2, entry2_low, entry2_high); ++#ifdef __i386__ ++ union ++ { ++ LDT_ENTRY entry; ++ ULONG dw[2]; ++ } sel; ++ ++ TRACE("(%x,%x,%x,%x,%x,%x)\n", selector1, entry1_low, entry1_high, selector2, entry2_low, entry2_high); + ++ if (selector1) ++ { ++ sel.dw[0] = entry1_low; ++ sel.dw[1] = entry1_high; ++ if (wine_ldt_set_entry(selector1, &sel.entry) < 0) ++ return STATUS_ACCESS_DENIED; ++ } ++ if (selector2) ++ { ++ sel.dw[0] = entry2_low; ++ sel.dw[1] = entry2_high; ++ if (wine_ldt_set_entry(selector2, &sel.entry) < 0) ++ return STATUS_ACCESS_DENIED; ++ } ++ return STATUS_SUCCESS; ++#else ++ FIXME("(%x,%x,%x,%x,%x,%x): stub\n", selector1, entry1_low, entry1_high, selector2, entry2_low, entry2_high); + return STATUS_NOT_IMPLEMENTED; ++#endif + } +-- +2.8.0 + diff --git a/patches/ntdll-NtSetLdtEntries/0003-libs-wine-Allow-to-modify-reserved-LDT-entries.patch b/patches/ntdll-NtSetLdtEntries/0003-libs-wine-Allow-to-modify-reserved-LDT-entries.patch new file mode 100644 index 00000000..054803a8 --- /dev/null +++ b/patches/ntdll-NtSetLdtEntries/0003-libs-wine-Allow-to-modify-reserved-LDT-entries.patch @@ -0,0 +1,68 @@ +From 36cdcc900c03de3e2e27a16252242a7a5ec55513 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Thu, 28 Apr 2016 17:01:16 +0200 +Subject: libs/wine: Allow to modify reserved LDT entries. + +Some implementation notes: + +1. Some copy protections call NtSetLdtEntries(0x000f) and then with 'retf' +instruction jump to that selector expecting that it works (the tests show that +NtSetLdtEntries(0x000f,0x001f) should succeed). In order to make this work a +limitation to set only selectors > LDT_FIRST_ENTRY (512) in wine_ldt_set_entry() +was removed. + +2. wine_ldt_set_entry() was made to always mark modified selector entries as +WINE_LDT_FLAGS_ALLOCATED, otherwise get_selector_entry() server call returns +entries without that flag set and NtQueryInformationThread(ThreadDescriptorTableEntry) +fails. +--- + dlls/kernel32/tests/thread.c | 4 ---- + libs/wine/ldt.c | 4 +--- + 2 files changed, 1 insertion(+), 7 deletions(-) + +diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c +index 981e3c4..6efc52a 100644 +--- a/dlls/kernel32/tests/thread.c ++++ b/dlls/kernel32/tests/thread.c +@@ -1163,16 +1163,12 @@ static void test_NtSetLdtEntries(void) + { + memset(&sel.entry, 0x9a, sizeof(sel.entry)); + ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry); +- todo_wine + ok(ret, "GetThreadSelectorEntry failed\n"); +- todo_wine + ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); + + memset(&sel.entry, 0x9a, sizeof(sel.entry)); + ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry); +- todo_wine + ok(ret, "GetThreadSelectorEntry failed\n"); +- todo_wine + ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); + } + } +diff --git a/libs/wine/ldt.c b/libs/wine/ldt.c +index 0946407..8ac779a 100644 +--- a/libs/wine/ldt.c ++++ b/libs/wine/ldt.c +@@ -169,8 +169,6 @@ static int internal_set_entry( unsigned short sel, const LDT_ENTRY *entry ) + { + int ret = 0, index = sel >> 3; + +- if (index < LDT_FIRST_ENTRY) return 0; /* cannot modify reserved entries */ +- + #ifdef linux + { + struct modify_ldt_s ldt_info; +@@ -222,7 +220,7 @@ static int internal_set_entry( unsigned short sel, const LDT_ENTRY *entry ) + wine_ldt_copy.limit[index] = wine_ldt_get_limit(entry); + wine_ldt_copy.flags[index] = (entry->HighWord.Bits.Type | + (entry->HighWord.Bits.Default_Big ? WINE_LDT_FLAGS_32BIT : 0) | +- (wine_ldt_copy.flags[index] & WINE_LDT_FLAGS_ALLOCATED)); ++ WINE_LDT_FLAGS_ALLOCATED); + } + return ret; + } +-- +2.8.0 + diff --git a/patches/ntdll-NtSetLdtEntries/0004-ntdll-Export-NtSetLdtEntries-only-on-i386.patch b/patches/ntdll-NtSetLdtEntries/0004-ntdll-Export-NtSetLdtEntries-only-on-i386.patch new file mode 100644 index 00000000..f055aa29 --- /dev/null +++ b/patches/ntdll-NtSetLdtEntries/0004-ntdll-Export-NtSetLdtEntries-only-on-i386.patch @@ -0,0 +1,67 @@ +From 9a0e823dfa31ea24a3e697bf3a3914011947c3e4 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 28 Apr 2016 17:07:35 +0200 +Subject: ntdll: Export NtSetLdtEntries only on i386. + +--- + dlls/ntdll/nt.c | 9 ++++----- + dlls/ntdll/ntdll.spec | 4 ++-- + 2 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c +index fbea627..8238932 100644 +--- a/dlls/ntdll/nt.c ++++ b/dlls/ntdll/nt.c +@@ -2784,6 +2784,8 @@ NTSTATUS WINAPI NtSystemDebugControl(SYSDBG_COMMAND command, PVOID inbuffer, ULO + return STATUS_NOT_IMPLEMENTED; + } + ++#ifdef __i386__ ++ + /****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) +@@ -2791,7 +2793,6 @@ NTSTATUS WINAPI NtSystemDebugControl(SYSDBG_COMMAND command, PVOID inbuffer, ULO + NTSTATUS WINAPI NtSetLdtEntries(ULONG selector1, ULONG entry1_low, ULONG entry1_high, + ULONG selector2, ULONG entry2_low, ULONG entry2_high) + { +-#ifdef __i386__ + union + { + LDT_ENTRY entry; +@@ -2815,8 +2816,6 @@ NTSTATUS WINAPI NtSetLdtEntries(ULONG selector1, ULONG entry1_low, ULONG entry1_ + return STATUS_ACCESS_DENIED; + } + return STATUS_SUCCESS; +-#else +- FIXME("(%x,%x,%x,%x,%x,%x): stub\n", selector1, entry1_low, entry1_high, selector2, entry2_low, entry2_high); +- return STATUS_NOT_IMPLEMENTED; +-#endif + } ++ ++#endif /* __i386__ */ +diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec +index 01c84c6..d4c4d52 100644 +--- a/dlls/ntdll/ntdll.spec ++++ b/dlls/ntdll/ntdll.spec +@@ -340,7 +340,7 @@ + @ stdcall NtSetInformationToken(long long ptr long) + @ stdcall NtSetIntervalProfile(long long) + @ stdcall NtSetIoCompletion(ptr long ptr long long) +-@ stdcall NtSetLdtEntries(long long long long long long) ++@ stdcall -i386 NtSetLdtEntries(long long long long long long) + @ stub NtSetLowEventPair + @ stub NtSetLowWaitHighEventPair + @ stub NtSetLowWaitHighThread +@@ -1261,7 +1261,7 @@ + @ stdcall ZwSetInformationToken(long long ptr long) NtSetInformationToken + @ stdcall ZwSetIntervalProfile(long long) NtSetIntervalProfile + @ stdcall ZwSetIoCompletion(ptr long ptr long long) NtSetIoCompletion +-@ stdcall ZwSetLdtEntries(long long long long long long) NtSetLdtEntries ++@ stdcall -i386 ZwSetLdtEntries(long long long long long long) NtSetLdtEntries + @ stub ZwSetLowEventPair + @ stub ZwSetLowWaitHighEventPair + @ stub ZwSetLowWaitHighThread +-- +2.8.0 + diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 812c2070..d735773e 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -4957,12 +4957,19 @@ fi # | * [#26268] Add stub for NtSetLdtEntries/ZwSetLdtEntries # | # | Modified files: -# | * dlls/ntdll/nt.c, dlls/ntdll/ntdll.spec, include/ddk/wdm.h, include/winternl.h +# | * dlls/kernel32/tests/thread.c, dlls/ntdll/nt.c, dlls/ntdll/ntdll.spec, include/ddk/wdm.h, include/winternl.h, +# | libs/wine/ldt.c # | if test "$enable_ntdll_NtSetLdtEntries" -eq 1; then patch_apply ntdll-NtSetLdtEntries/0001-ntdll-add-NtSetLdtEntries-ZwSetLdtEntries-stub-try-2.patch + patch_apply ntdll-NtSetLdtEntries/0002-ntdll-Implement-NtSetLdtEntries.patch + patch_apply ntdll-NtSetLdtEntries/0003-libs-wine-Allow-to-modify-reserved-LDT-entries.patch + patch_apply ntdll-NtSetLdtEntries/0004-ntdll-Export-NtSetLdtEntries-only-on-i386.patch ( echo '+ { "Austin English", "ntdll: Add NtSetLdtEntries/ZwSetLdtEntries stub.", 2 },'; + echo '+ { "Dmitry Timoshkov", "ntdll: Implement NtSetLdtEntries.", 1 },'; + echo '+ { "Dmitry Timoshkov", "libs/wine: Allow to modify reserved LDT entries.", 1 },'; + echo '+ { "Sebastian Lackner", "ntdll: Export NtSetLdtEntries only on i386.", 1 },'; ) >> "$patchlist" fi