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;
}
|