From: Elizabeth Figura <zfigura@codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48291 --- dlls/ntdll/tests/exception.c | 1 - dlls/ntdll/unix/signal_x86_64.c | 86 +++++++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index b114b82cd4b..5ba23d38d34 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -6237,7 +6237,6 @@ static void test_direct_syscalls(void) func = code_mem; func(find_syscall_nr("NtSetEvent"), event, NULL); - todo_wine ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event not signaled.\n"); CloseHandle(event); } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 740df80341f..a9e2fb04968 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -35,6 +35,9 @@ #include <sys/types.h> #include <sys/mman.h> #include <unistd.h> +#ifdef HAVE_LINK_H +# include <link.h> +#endif #ifdef HAVE_MACHINE_SYSARCH_H # include <machine/sysarch.h> #endif @@ -44,6 +47,9 @@ #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> #endif +#ifdef HAVE_SYS_PRCTL_H +# include <sys/prctl.h> +#endif #ifdef HAVE_SYSCALL_H # include <syscall.h> #else @@ -506,6 +512,7 @@ struct amd64_thread_data void **instrumentation_callback; /* 0330 */ DWORD fs; /* 0338 WOW TEB selector */ DWORD mxcsr; /* 033c Unix-side mxcsr register */ + char syscall_dispatch; /* 0340 */ }; C_ASSERT( sizeof(struct amd64_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) ); @@ -908,10 +915,11 @@ static inline ucontext_t *init_handler( void *sigcontext ) { clear_alignment_flag(); #ifdef __linux__ - if (fs32_sel) { - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&get_current_teb()->GdiTebBatch; - arch_prctl( ARCH_SET_FS, ((struct amd64_thread_data *)thread_data->cpu_data)->pthread_teb ); + struct amd64_thread_data *thread_data = (struct amd64_thread_data *)&get_current_teb()->GdiTebBatch; + thread_data->syscall_dispatch = SYSCALL_DISPATCH_FILTER_ALLOW; + if (fs32_sel) + arch_prctl( ARCH_SET_FS, thread_data->pthread_teb ); } #elif defined __APPLE__ { @@ -938,10 +946,14 @@ static inline ucontext_t *init_handler( void *sigcontext ) static inline void leave_handler( ucontext_t *sigcontext ) { #ifdef __linux__ - if (fs32_sel && - !is_inside_signal_stack( (void *)RSP_sig(sigcontext )) && + struct amd64_thread_data *thread_data = (struct amd64_thread_data *)&NtCurrentTeb()->GdiTebBatch; + if (!is_inside_signal_stack( (void *)RSP_sig(sigcontext )) && !is_inside_syscall( RSP_sig(sigcontext) )) - __asm__ volatile( "movw %0,%%fs" :: "r" (fs32_sel) ); + { + thread_data->syscall_dispatch = SYSCALL_DISPATCH_FILTER_BLOCK; + if (fs32_sel) + __asm__ volatile( "movw %0,%%fs" :: "r" (fs32_sel) ); + } #elif defined __APPLE__ if (!is_inside_signal_stack( (void *)RSP_sig(sigcontext )) && !is_inside_syscall( RSP_sig(sigcontext ))) @@ -1802,6 +1814,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movq 0x98(%r14),%rbp\n\t" /* prev_frame->rbp */ "ldmxcsr 0xd8(%r14)\n\t" /* prev_frame->xsave.MxCsr */ #ifdef __linux__ + "movb $1,0x340(%r13)\n\t" /* amd64_thread_data()->syscall_dispatch */ "movw 0x338(%r13),%ax\n" /* amd64_thread_data()->fs */ "testw %ax,%ax\n\t" "jz 1f\n\t" @@ -2682,12 +2695,12 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(PR_SET_SYSCALL_USER_DISPATCH) /********************************************************************** * sigsys_handler * * Handler for SIGSYS, signals that a non-existent system call was invoked. - * Only called on macOS 14 Sonoma and later. + * On Mac, this is only called on macOS 14 Sonoma and later. */ static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { @@ -2879,7 +2892,7 @@ void signal_init_process(void) if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(PR_SET_SYSCALL_USER_DISPATCH) sig_act.sa_sigaction = sigsys_handler; if (sigaction( SIGSYS, &sig_act, NULL ) == -1) goto error; #endif @@ -2891,6 +2904,53 @@ void signal_init_process(void) } +#ifdef PR_SET_SYSCALL_USER_DISPATCH + +struct libc_addr_ctx +{ + uintptr_t addr, size; +}; + +static int libc_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) +{ + struct libc_addr_ctx *ctx = arg; + const char *p; + + if ((p = strrchr( info->dlpi_name, '/' ))) + ++p; + else + p = info->dlpi_name; + + if (strcmp( p, "libc.so.6" )) + return 0; + + ctx->addr = info->dlpi_addr; + ctx->size = 0; + for (unsigned int i = 0; i < info->dlpi_phnum; ++i) + ctx->size = max( ctx->size, info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz ); + + return 1; +} + +static void init_linux_syscall_dispatch( struct amd64_thread_data *thread_data ) +{ + struct libc_addr_ctx ctx; + + if (!dl_iterate_phdr( libc_addr_cb, &ctx )) + { + WARN_(seh)( "could not find libc\n" ); + return; + } + + if (prctl( PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, + ctx.addr, ctx.size, &thread_data->syscall_dispatch ) < 0) + WARN_(seh)( "could not enable syscall user dispatch\n" ); + + thread_data->syscall_dispatch = SYSCALL_DISPATCH_FILTER_BLOCK; +} +#endif + + /*********************************************************************** * init_syscall_frame */ @@ -2977,6 +3037,10 @@ void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, } pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL ); + +#ifdef PR_SET_SYSCALL_USER_DISPATCH + init_linux_syscall_dispatch( thread_data ); +#endif } @@ -3115,6 +3179,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, * (on macOS, signal handlers set gsbase to pthread_teb when on the kernel stack). */ #ifdef __linux__ + "movb $0,0x340(%r13)\n\t" /* amd64_thread_data()->syscall_dispatch */ "movq 0x320(%r13),%rsi\n\t" /* amd64_thread_data()->pthread_teb */ "testq %rsi,%rsi\n\t" "jz 2f\n\t" @@ -3174,6 +3239,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI_CFA_IS_AT2(rcx, 0xa8, 0x01) /* frame->syscall_cfa */ "leaq 0x70(%rcx),%rsp\n\t" /* %rsp > frame means no longer inside syscall */ #ifdef __linux__ + "movb $1,0x340(%r13)\n\t" /* amd64_thread_data()->syscall_dispatch */ "movw 0x338(%r13),%dx\n" /* amd64_thread_data()->fs */ "testw %dx,%dx\n\t" "jz 1f\n\t" @@ -3404,6 +3470,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, __ASM_CFI(".cfi_undefined %rdi\n\t") __ASM_CFI(".cfi_undefined %rsi\n\t") #ifdef __linux__ + "movb $0,0x340(%r13)\n\t" /* amd64_thread_data()->syscall_dispatch */ "movq 0x320(%r13),%rsi\n\t" /* amd64_thread_data()->pthread_teb */ "testq %rsi,%rsi\n\t" "jz 2f\n\t" @@ -3442,6 +3509,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, "movq 0x88(%rcx),%rsp\n\t" __ASM_CFI(".cfi_restore_state\n\t") #ifdef __linux__ + "movb $1,0x340(%r13)\n\t" /* amd64_thread_data()->syscall_dispatch */ "movw 0x338(%r13),%dx\n" /* amd64_thread_data()->fs */ "testw %dx,%dx\n\t" "jz 1f\n\t" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10330