From 01873109662eb7f5879eb72fdf1f55bbdaef0329 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 1 Apr 2020 12:33:37 +0200 Subject: [PATCH] ntdll: Implement NtSetLdtEntries(). Signed-off-by: Alexandre Julliard --- dlls/ntdll/nt.c | 12 ---- dlls/ntdll/ntdll.spec | 2 +- dlls/ntdll/signal_arm.c | 9 +++ dlls/ntdll/signal_arm64.c | 9 +++ dlls/ntdll/signal_i386.c | 110 ++++++++++++++++++++++++++++++++++++ dlls/ntdll/signal_powerpc.c | 9 +++ dlls/ntdll/signal_x86_64.c | 9 +++ include/winternl.h | 2 +- 8 files changed, 148 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index 474eb510ec6..6c95517e791 100644 --- a/dlls/ntdll/nt.c +++ b/dlls/ntdll/nt.c @@ -3720,15 +3720,3 @@ NTSTATUS WINAPI NtSystemDebugControl(SYSDBG_COMMAND command, PVOID inbuffer, ULO return STATUS_NOT_IMPLEMENTED; } - -/****************************************************************************** - * NtSetLdtEntries (NTDLL.@) - * ZwSetLdtEntries (NTDLL.@) - */ -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); - - return STATUS_NOT_IMPLEMENTED; -} diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 0ea72e3aefa..13b0317744a 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -380,7 +380,7 @@ @ stdcall NtSetInformationToken(long long ptr long) @ stdcall NtSetIntervalProfile(long long) @ stdcall NtSetIoCompletion(ptr long long long long) -@ stdcall NtSetLdtEntries(long long long long long long) +@ stdcall NtSetLdtEntries(long int64 long int64) @ stub NtSetLowEventPair @ stub NtSetLowWaitHighEventPair @ stub NtSetLowWaitHighThread diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 6ab8888b8f6..63c008224df 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -1285,6 +1285,15 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_ return STATUS_NOT_IMPLEMENTED; } +/****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) + */ +NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) +{ + return STATUS_NOT_IMPLEMENTED; +} + /********************************************************************** * DbgBreakPoint (NTDLL.@) */ diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index 226cd7c8fe7..5fffd45f7bd 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -2113,6 +2113,15 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_ return STATUS_NOT_IMPLEMENTED; } +/****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) + */ +NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) +{ + return STATUS_NOT_IMPLEMENTED; +} + /********************************************************************** * DbgBreakPoint (NTDLL.@) */ diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index dcd4d553159..60f4637e2d4 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -185,6 +185,30 @@ __ASM_GLOBAL_FUNC( rt_sigreturn, "int $0x80" ); #endif +struct modify_ldt_s +{ + unsigned int entry_number; + void *base_addr; + unsigned int limit; + unsigned int seg_32bit : 1; + unsigned int contents : 2; + unsigned int read_exec_only : 1; + unsigned int limit_in_pages : 1; + unsigned int seg_not_present : 1; + unsigned int usable : 1; + unsigned int garbage : 25; +}; + +static inline int modify_ldt( int func, struct modify_ldt_s *ptr, unsigned long count ) +{ + return syscall( 123 /* SYS_modify_ldt */, func, ptr, count ); +} + +static inline int set_thread_area( struct modify_ldt_s *ptr ) +{ + return syscall( 243 /* SYS_set_thread_area */, ptr ); +} + #elif defined (__BSDI__) #include @@ -214,6 +238,8 @@ typedef struct trapframe ucontext_t; #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) #include +#include +#include #define EAX_sig(context) ((context)->uc_mcontext.mc_eax) #define EBX_sig(context) ((context)->uc_mcontext.mc_ebx) @@ -242,6 +268,9 @@ typedef struct trapframe ucontext_t; #elif defined (__OpenBSD__) +#include +#include + #define EAX_sig(context) ((context)->sc_eax) #define EBX_sig(context) ((context)->sc_ebx) #define ECX_sig(context) ((context)->sc_ecx) @@ -318,6 +347,8 @@ typedef struct trapframe ucontext_t; #elif defined (__APPLE__) +#include + /* work around silly renaming of struct members in OS X 10.5 */ #if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) #define EAX_sig(context) ((context)->uc_mcontext->__ss.__eax) @@ -365,6 +396,9 @@ typedef struct trapframe ucontext_t; #elif defined(__NetBSD__) +#include +#include + #define EAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EAX]) #define EBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBX]) #define ECX_sig(context) ((context)->uc_mcontext.__gregs[_REG_ECX]) @@ -394,6 +428,9 @@ typedef struct trapframe ucontext_t; #elif defined(__GNU__) +#include +#include + #define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX]) #define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX]) #define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX]) @@ -440,6 +477,8 @@ static const size_t teb_size = 4096; /* we reserve one page for the TEB */ static size_t signal_stack_mask; static size_t signal_stack_size; +static ULONG first_ldt_entry = 32; + static wine_signal_handler handlers[256]; enum i386_trap_code @@ -2294,6 +2333,58 @@ static LDT_ENTRY ldt_make_entry( void *base, unsigned int limit, unsigned char f return entry; } +static void ldt_set_entry( WORD sel, LDT_ENTRY entry ) +{ + int index = sel >> 3; + +#ifdef linux + struct modify_ldt_s ldt_info = { index }; + + ldt_info.base_addr = wine_ldt_get_base( &entry ); + ldt_info.limit = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16); + ldt_info.seg_32bit = entry.HighWord.Bits.Default_Big; + ldt_info.contents = (entry.HighWord.Bits.Type >> 2) & 3; + ldt_info.read_exec_only = !(entry.HighWord.Bits.Type & 2); + ldt_info.limit_in_pages = entry.HighWord.Bits.Granularity; + ldt_info.seg_not_present = !entry.HighWord.Bits.Pres; + ldt_info.usable = entry.HighWord.Bits.Sys; + if (modify_ldt( 0x11, &ldt_info, sizeof(ldt_info) ) < 0) perror( "modify_ldt" ); +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) + /* The kernel will only let us set LDTs with user priority level */ + if (entry.HighWord.Bits.Pres && entry.HighWord.Bits.Dpl != 3) entry.HighWord.Bits.Dpl = 3; + if (i386_set_ldt(index, (union descriptor *)&entry, 1) < 0) + { + perror("i386_set_ldt"); + fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" ); + exit(1); + } +#elif defined(__svr4__) || defined(_SCO_DS) + struct ssd ldt_mod; + + ldt_mod.sel = sel; + ldt_mod.bo = (unsigned long)wine_ldt_get_base(&entry); + ldt_mod.ls = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16); + ldt_mod.acc1 = entry.HighWord.Bytes.Flags1; + ldt_mod.acc2 = entry.HighWord.Bytes.Flags2 >> 4; + if (sysi86(SI86DSCR, &ldt_mod) == -1) perror("sysi86"); +#elif defined(__APPLE__) + if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt"); +#elif defined(__GNU__) + if (i386_set_ldt(mach_thread_self(), sel, (descriptor_list_t)&entry, 1) != KERN_SUCCESS) + perror("i386_set_ldt"); +#else + fprintf( stderr, "No LDT support on this platform\n" ); + exit(1); +#endif + + wine_ldt_copy.base[index] = wine_ldt_get_base( &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_FLAGS_ALLOCATED); +} + + /********************************************************************** * get_thread_ldt_entry */ @@ -2342,6 +2433,25 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_ return status; } + +/****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) + */ +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 ); + if (sel2) ldt_set_entry( sel2, entry2 ); + ldt_unlock(); + return STATUS_SUCCESS; +} + + /********************************************************************** * signal_alloc_thread */ diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index 45b2f4a43e1..ee765e226b1 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -1263,6 +1263,15 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_ return STATUS_NOT_IMPLEMENTED; } +/****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) + */ +NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) +{ + return STATUS_NOT_IMPLEMENTED; +} + /********************************************************************** * DbgBreakPoint (NTDLL.@) */ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index df204b32d74..89caca9f30f 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -4286,6 +4286,15 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_ return STATUS_NOT_IMPLEMENTED; } +/****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) + */ +NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) +{ + return STATUS_NOT_IMPLEMENTED; +} + /********************************************************************** * DbgBreakPoint (NTDLL.@) */ diff --git a/include/winternl.h b/include/winternl.h index 19e8965e99f..e4c611e4af9 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2585,7 +2585,7 @@ NTSYSAPI NTSTATUS WINAPI NtSetInformationThread(HANDLE,THREADINFOCLASS,LPCVOID, NTSYSAPI NTSTATUS WINAPI NtSetInformationToken(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,ULONG); NTSYSAPI NTSTATUS WINAPI NtSetIntervalProfile(ULONG,KPROFILE_SOURCE); NTSYSAPI NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,ULONG_PTR,NTSTATUS,SIZE_T); -NTSYSAPI NTSTATUS WINAPI NtSetLdtEntries(ULONG,ULONG,ULONG,ULONG,ULONG,ULONG); +NTSYSAPI NTSTATUS WINAPI NtSetLdtEntries(ULONG,LDT_ENTRY,ULONG,LDT_ENTRY); NTSYSAPI NTSTATUS WINAPI NtSetLowEventPair(HANDLE); NTSYSAPI NTSTATUS WINAPI NtSetLowWaitHighEventPair(HANDLE); NTSYSAPI NTSTATUS WINAPI NtSetLowWaitHighThread(VOID);