ntdll-NtSetLdtEntries: Update patchset and add actual implementation of NtSetLdtEntries.

This commit is contained in:
Sebastian Lackner 2016-04-28 17:13:03 +02:00
parent 0712486b63
commit 51b447a55f
4 changed files with 313 additions and 1 deletions

View File

@ -0,0 +1,170 @@
From aadd7b2c0ca9bf60d64c3ed4e0722de3899b8c13 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
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

View File

@ -0,0 +1,68 @@
From 36cdcc900c03de3e2e27a16252242a7a5ec55513 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
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

View File

@ -0,0 +1,67 @@
From 9a0e823dfa31ea24a3e697bf3a3914011947c3e4 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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

View File

@ -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