diff --git a/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch b/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch index 014d6a46..58dece2c 100644 --- a/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch +++ b/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch @@ -1,19 +1,18 @@ -From d7be25a11e01c6f223b39df2fb45cc9f531f6c83 Mon Sep 17 00:00:00 2001 +From a53a38937f258294b4c98b3de57f8734158f5b6b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Jul 2020 15:00:34 +0300 Subject: [PATCH] ntdll: Support x86_64 syscall emulation. --- configure.ac | 1 + - dlls/ntdll/unix/signal_x86_64.c | 123 ++++++++++++++++++++++++++++++++ - tools/winebuild/import.c | 3 +- - 3 files changed, 125 insertions(+), 2 deletions(-) + dlls/ntdll/unix/signal_x86_64.c | 185 ++++++++++++++++++++++++++++++++ + 2 files changed, 186 insertions(+) diff --git a/configure.ac b/configure.ac -index 5a5d88f10b0..7ae43b0c593 100644 +index db7753959d7..08dd970506e 100644 --- a/configure.ac +++ b/configure.ac -@@ -448,6 +448,7 @@ AC_CHECK_HEADERS(\ +@@ -445,6 +445,7 @@ AC_CHECK_HEADERS(\ linux/ioctl.h \ linux/major.h \ linux/param.h \ @@ -22,10 +21,10 @@ index 5a5d88f10b0..7ae43b0c593 100644 linux/types.h \ linux/ucdrom.h \ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 06d99545913..9a46b4a50b0 100644 +index c726b962074..ae985625e50 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -27,11 +27,13 @@ +@@ -27,6 +27,7 @@ #include "config.h" #include @@ -33,13 +32,16 @@ index 06d99545913..9a46b4a50b0 100644 #include #include #include - #include +@@ -34,6 +35,8 @@ #include -+#include #include #include ++#include ++#include #include -@@ -65,6 +67,13 @@ + #ifdef HAVE_MACHINE_SYSARCH_H + # include +@@ -65,6 +68,14 @@ # include #endif @@ -48,29 +50,34 @@ index 06d99545913..9a46b4a50b0 100644 +# include +# include +# include ++# include +#endif + #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "ntstatus.h" -@@ -2432,6 +2441,118 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) +@@ -1807,6 +1818,179 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) return 0; } +#ifdef HAVE_SECCOMP +static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ ++ extern void __wine_syscall_dispatcher_prolog_end(void); ++ struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + ucontext_t *ctx = sigcontext; -+ void ***rsp; + -+ TRACE("SIGSYS, rax %#llx, rip %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX], ++ TRACE_(seh)("SIGSYS, rax %#llx, rip %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX], + ctx->uc_mcontext.gregs[REG_RIP]); + -+ rsp = (void ***)&ctx->uc_mcontext.gregs[REG_RSP]; -+ *rsp -= 1; -+ **rsp = (void *)(ctx->uc_mcontext.gregs[REG_RIP] + 0xb); -+ -+ ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher; ++ frame->rip = ctx->uc_mcontext.gregs[REG_RIP] + 0xb; ++ frame->rcx = ctx->uc_mcontext.gregs[REG_RIP]; ++ frame->eflags = ctx->uc_mcontext.gregs[REG_EFL]; ++ frame->restore_flags = 0; ++ ctx->uc_mcontext.gregs[REG_RCX] = (ULONG_PTR)frame; ++ ctx->uc_mcontext.gregs[REG_R11] = frame->eflags; ++ ctx->uc_mcontext.gregs[REG_EFL] &= ~0x100; /* clear single-step flag */ ++ ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher_prolog_end; +} +#endif + @@ -92,20 +99,20 @@ index 06d99545913..9a46b4a50b0 100644 + fd = open("/proc/sys/net/core/bpf_jit_enable", O_RDONLY); + if (fd == -1) + { -+ WARN("Could not open /proc/sys/net/core/bpf_jit_enable.\n"); ++ WARN_(seh)("Could not open /proc/sys/net/core/bpf_jit_enable.\n"); + return; + } + + if (read(fd, &enabled, sizeof(enabled)) == sizeof(enabled)) + { -+ TRACE("enabled %#x.\n", enabled); ++ TRACE_(seh)("enabled %#x.\n", enabled); + + if (enabled != '1') -+ ERR("BPF JIT is not enabled in the kernel, enable it to reduce syscall emulation overhead.\n"); ++ ERR_(seh)("BPF JIT is not enabled in the kernel, enable it to reduce syscall emulation overhead.\n"); + } + else + { -+ WARN("Could not read /proc/sys/net/core/bpf_jit_enable.\n"); ++ WARN_(seh)("Could not read /proc/sys/net/core/bpf_jit_enable.\n"); + } + close(fd); +} @@ -120,59 +127,116 @@ index 06d99545913..9a46b4a50b0 100644 +# ifndef SECCOMP_SET_MODE_FILTER +# define SECCOMP_SET_MODE_FILTER 1 +# endif ++ static const BYTE syscall_trap_test[] = ++ { ++ 0x48, 0x89, 0xc8, /* mov %rcx, %rax */ ++ 0x0f, 0x05, /* syscall */ ++ 0xc3, /* retq */ ++ }; + static const unsigned int flags = SECCOMP_FILTER_FLAG_SPEC_ALLOW; ++ ++#define NATIVE_SYSCALL_ADDRESS_START 0x700000000000 ++ + static struct sock_filter filter[] = + { -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -+ (offsetof(struct seccomp_data, nr))), -+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0xf000, 0, 1), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), ++ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), ++ /* Native libs are loaded at high addresses. */ ++ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, NATIVE_SYSCALL_ADDRESS_START >> 32, 0, 1), ++ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), ++ /* Allow i386. */ ++ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)), ++ BPF_JUMP (BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), ++ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), ++ /* Allow wine64-preloader */ ++ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer)), ++ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x7d400000, 1, 0), ++ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), ++ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x7d402000, 0, 1), ++ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), ++ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + }; ++ long (WINAPI *test_syscall)(long sc_number); + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + struct sock_fprog prog; + NTSTATUS status; + ++ if ((ULONG_PTR)sc_seccomp < NATIVE_SYSCALL_ADDRESS_START ++ || (ULONG_PTR)syscall < NATIVE_SYSCALL_ADDRESS_START) ++ { ++ ERR_(seh)("Native libs are being loaded in low addresses, sc_seccomp %p, syscall %p, not installing seccomp.\n", ++ sc_seccomp, syscall); ++ ERR_(seh)("The known reasons are /proc/sys/vm/legacy_va_layout set to 1 or 'ulimit -s' being 'unlimited'.\n"); ++ return; ++ } ++ + sig_act->sa_sigaction = sigsys_handler; ++ memset(&prog, 0, sizeof(prog)); ++ + sigaction(SIGSYS, sig_act, NULL); + + frame->syscall_flags = syscall_flags; + frame->syscall_table = KeServiceDescriptorTable; + -+ if ((status = syscall(0xffff)) == STATUS_INVALID_PARAMETER) ++ test_syscall = mmap((void *)0x600000000000, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANON, -1, 0); ++ if (test_syscall != (void *)0x600000000000) + { -+ TRACE("Seccomp filters already installed.\n"); -+ return; ++ int ret; ++ ++ ERR("Could not allocate test syscall, falling back to seccomp presence check, test_syscall %p, errno %d.\n", ++ test_syscall, errno); ++ if (test_syscall != MAP_FAILED) munmap(test_syscall, 0x1000); ++ ++ if ((ret = prctl(PR_GET_SECCOMP, 0, NULL, 0, 0))) ++ { ++ if (ret == 2) ++ TRACE_(seh)("Seccomp filters already installed.\n"); ++ else ++ ERR_(seh)("Seccomp filters cannot be installed, ret %d, error %s.\n", ret, strerror(errno)); ++ return; ++ } + } -+ if (status != -ENOSYS && (status != -1 || errno != ENOSYS)) ++ else + { -+ ERR("Unexpected status %#x, errno %d.\n", status, errno); -+ return; ++ memcpy(test_syscall, syscall_trap_test, sizeof(syscall_trap_test)); ++ status = test_syscall(0xffff); ++ munmap(test_syscall, 0x1000); ++ if (status == STATUS_INVALID_PARAMETER) ++ { ++ TRACE_(seh)("Seccomp filters already installed.\n"); ++ return; ++ } ++ if (status != -ENOSYS && (status != -1 || errno != ENOSYS)) ++ { ++ ERR_(seh)("Unexpected status %#x, errno %d.\n", status, errno); ++ return; ++ } + } + -+ memset(&prog, 0, sizeof(prog)); ++ TRACE_(seh)("Installing seccomp filters.\n"); ++ + prog.len = ARRAY_SIZE(filter); + prog.filter = filter; + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) + { -+ ERR("prctl(PR_SET_NO_NEW_PRIVS, ...): %s.\n", strerror(errno)); ++ ERR_(seh)("prctl(PR_SET_NO_NEW_PRIVS, ...): %s.\n", strerror(errno)); + return; + } + if (sc_seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog)) + { -+ ERR("prctl(PR_SET_SECCOMP, ...): %s.\n", strerror(errno)); ++ ERR_(seh)("prctl(PR_SET_SECCOMP, ...): %s.\n", strerror(errno)); + return; + } + check_bpf_jit_enable(); +#else -+ WARN("Built without seccomp.\n"); ++ WARN_(seh)("Built without seccomp.\n"); +#endif +} /*********************************************************************** * handle_interrupt -@@ -3010,6 +3131,7 @@ void signal_init_process(void) +@@ -2479,6 +2663,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; @@ -180,35 +244,6 @@ index 06d99545913..9a46b4a50b0 100644 return; error: -@@ -3228,6 +3350,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, - "leaq 0x28(%rsp),%rsi\n\t" /* first argument */ - "movq %rcx,%rsp\n\t" - "movq 0x00(%rcx),%rax\n\t" -+ "subq $0xf000,%rax\n\t" - "movq 0x18(%rcx),%rdx\n\t" - "movl %eax,%ebx\n\t" - "shrl $8,%ebx\n\t" -diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c -index c876d51f8e6..37f1465a139 100644 ---- a/tools/winebuild/import.c -+++ b/tools/winebuild/import.c -@@ -1366,7 +1366,6 @@ static int cmp_link_name( const void *e1, const void *e2 ) - return strcmp( odp1->link_name, odp2->link_name ); - } - -- - /* output the functions for system calls */ - void output_syscalls( DLLSPEC *spec ) - { -@@ -1424,7 +1423,7 @@ void output_syscalls( DLLSPEC *spec ) - * validate that instruction, we can just put a jmp there instead. */ - output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */ - output( "\t.byte 0xb8\n" ); /* movl $i,%eax */ -- output( "\t.long %u\n", id ); -+ output( "\t.long %u\n", 0xf000 + id ); - output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */ - output( "\t.byte 0x75,0x03\n" ); /* jne 1f */ - output( "\t.byte 0x0f,0x05\n" ); /* syscall */ -- -2.33.0 +2.38.1 diff --git a/patches/ntdll-Syscall_Emulation/definition b/patches/ntdll-Syscall_Emulation/definition index da459e75..89b59eb0 100644 --- a/patches/ntdll-Syscall_Emulation/definition +++ b/patches/ntdll-Syscall_Emulation/definition @@ -1,3 +1 @@ Fixes: [48291] Detroit: Become Human crashes on launch -# Causing steam to networking service to crash. -Disabled: True diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 634f9786..78c92abb 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -51,7 +51,7 @@ usage() # Get the upstream commit sha upstream_commit() { - echo "384b0b35c357ca31ccb080162e1f39f93ec70054" + echo "053ee2d23d825f800baa16e455a218834aa2dec0" } # Show version information @@ -142,6 +142,7 @@ patch_enable_all () enable_ntdll_ProcessQuotaLimits="$1" enable_ntdll_RtlQueryPackageIdentity="$1" enable_ntdll_Serial_Port_Detection="$1" + enable_ntdll_Syscall_Emulation="$1" enable_ntdll_WRITECOPY="$1" enable_ntdll_ext4_case_folder="$1" enable_ntdll_wine_frames="$1" @@ -438,6 +439,9 @@ patch_enable () ntdll-Serial_Port_Detection) enable_ntdll_Serial_Port_Detection="$2" ;; + ntdll-Syscall_Emulation) + enable_ntdll_Syscall_Emulation="$2" + ;; ntdll-WRITECOPY) enable_ntdll_WRITECOPY="$2" ;; @@ -2209,6 +2213,18 @@ if test "$enable_ntdll_RtlQueryPackageIdentity" -eq 1; then patch_apply ntdll-RtlQueryPackageIdentity/0003-ntdll-tests-Add-basic-tests-for-RtlQueryPackageIdent.patch fi +# Patchset ntdll-Syscall_Emulation +# | +# | This patchset fixes the following Wine bugs: +# | * [#48291] Detroit: Become Human crashes on launch +# | +# | Modified files: +# | * configure.ac, dlls/ntdll/unix/signal_x86_64.c +# | +if test "$enable_ntdll_Syscall_Emulation" -eq 1; then + patch_apply ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch +fi + # Patchset ntdll-ext4-case-folder # | # | This patchset fixes the following Wine bugs: