summarylogtreecommitdiffstats
path: root/420CustomPatch1.diff
blob: 504eff1e76fcaab4e2ceb75ffbe978e05e29bb3e (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 --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index c5b2008e44..96ca266921 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -268,6 +268,77 @@ static void set_process_name( int argc, char *argv[] )
 }
 
 
+#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
+
+
 /***********************************************************************
  *           thread_init
  *
@@ -370,6 +441,10 @@ TEB *thread_init(void)
     __wine_user_shared_data();
     fill_cpu_info();
 
+#ifdef __i386__
+   seccomp_init();
+#endif
+
     return teb;
 }