From 338f514f1468d77ae19ac9bbe7ba7d2b018ec83c Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Thu, 28 Apr 2016 17:01:16 +0200 Subject: [PATCH] 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 ---- dlls/ntdll/signal_i386.c | 2 -- libs/wine/ldt.c | 4 +--- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index 70b22367e18..a454bf118cc 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -1325,16 +1325,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/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 2db76f0e250..fd1a764dacf 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -2614,8 +2614,6 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_ NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) { if (sel1 >> 16 || sel2 >> 16) return STATUS_INVALID_LDT_DESCRIPTOR; - if (sel1 && (sel1 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR; - if (sel2 && (sel2 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR; ldt_lock(); if (sel1) ldt_set_entry( sel1, entry1 ); diff --git a/libs/wine/ldt.c b/libs/wine/ldt.c index a8f4925019b..5e85c1137c8 100644 --- a/libs/wine/ldt.c +++ b/libs/wine/ldt.c @@ -225,8 +225,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; @@ -278,7 +276,7 @@ static int internal_set_entry( unsigned short sel, const LDT_ENTRY *entry ) wine_ldt_copy_obsolete.limit[index] = wine_ldt_get_limit(entry); wine_ldt_copy_obsolete.flags[index] = (entry->HighWord.Bits.Type | (entry->HighWord.Bits.Default_Big ? WINE_LDT_FLAGS_32BIT : 0) | - (wine_ldt_copy_obsolete.flags[index] & WINE_LDT_FLAGS_ALLOCATED)); + WINE_LDT_FLAGS_ALLOCATED); } return ret; } -- 2.25.1