summarylogtreecommitdiffstats
path: root/wine-lol-bug-47198-fix.patch
blob: 96220ed73eb10f8e248936b17295f2c15990cbe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
diff -U 3 -pr a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
--- a/dlls/ntdll/thread.c	2020-08-29 17:04:09.498850399 +0200
+++ b/dlls/ntdll/thread.c	2020-08-29 17:05:37.801890998 +0200
@@ -226,6 +226,77 @@ int __cdecl __wine_dbg_header( enum __wi
     return unix_funcs->dbg_header( cls, channel, function );
 }
 
+#ifdef __i386__
+#include <asm/ldt.h>
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+#include <linux/unistd.h>
+#include <sys/prctl.h>
+#include <errno.h>
+
+static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    ucontext_t *ctx = sigcontext;
+
+    WINE_ERR( "SIGSYS (%d)\n", ctx->uc_mcontext.gregs[REG_EAX] );
+
+    // FIXME Relay to actual Nt syscall.
+
+    ctx->uc_mcontext.gregs[REG_EAX] = 0;
+}
+
+// FIXME All of this code is i386 Linux-specific. It may want to live in
+//       signal_i386.c.
+void seccomp_init(void)
+{
+    int ret;
+    char *tcbhead;
+    struct sigaction sig_act;
+    // FIXME Allocate a range of syscall numbers for Wine, e.g. 1024+. This
+    //       will be necessary to distinguish Linux syscall numbers from Wine
+    //       syscall numbers.
+    struct sock_filter filter[] = {
+        { BPF_LD | BPF_W | BPF_ABS, 0, 0, 0 },
+        { BPF_JMP | BPF_JEQ, 1, 0, 173 },
+            { BPF_RET, 0, 0, SECCOMP_RET_ALLOW },
+        { BPF_LD | BPF_W | BPF_ABS, 0, 0, 4 },
+        { BPF_JMP | BPF_JEQ, 1, 0, AUDIT_ARCH_X86_64 },
+            { BPF_RET, 0, 0, SECCOMP_RET_ALLOW },
+        { BPF_RET, 0, 0, SECCOMP_RET_TRAP }
+    };
+    struct sock_fprog prog = { 7, filter };
+
+    // FIXME There is no way to remove a seccomp upon execve. This should not
+    //       have bad effects on non-Wine programs, provided we fix the syscall
+    //       numbering, but we may be adding the same seccomp filter multiple
+    //       times unnecessarily.
+    ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+    TRACE( "prctl(SET_NO_NEW_PRIVS) = %d, %d\n", ret, errno );
+    prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
+    TRACE( "prctl(SET_SECCOMP) = %d, %d\n", ret, errno );
+
+    sig_act.sa_mask = server_block_set;
+    sig_act.sa_flags = SA_SIGINFO | SA_RESTART;
+#ifdef SA_ONSTACK
+    sig_act.sa_flags |= SA_ONSTACK;
+#endif
+    sig_act.sa_sigaction = sigsys_handler;
+    ret = sigaction( SIGSYS, &sig_act, NULL );
+    TRACE( "sigaction(SIGSYS) = %d\n", ret );
+
+    asm ("mov %%gs:0, %0" : "=r" (tcbhead));
+    TRACE( "gs:0 = %p\n", tcbhead );
+
+    // FIXME Requires a patched version of glibc to expand the reserved size
+    //       at the top of (struct pthread). Upstream glibc only reserves 0x60
+    //       bytes on i386, and we require at least 0x68 bytes. The code below
+    //       assumes at least 0x6C bytes are reserved.
+    *(uint64_t *)(tcbhead + 0x60) = (uintptr_t)(tcbhead + 0x68);
+}
+#endif
+
+
 /***********************************************************************
  *		__wine_dbg_output  (NTDLL.@)
  */
@@ -430,6 +501,11 @@ TEB *thread_init(void)
     unix_funcs->dbg_init();
     unix_funcs->get_paths( &build_dir, &data_dir, &config_dir );
     fill_cpu_info();
+
+#ifdef __i386__
+   seccomp_init();
+#endif
+
     return teb;
 }