cosmetic cleanups
[tor.git] / src / common / sandbox.c
blob68be89e8816e895caaa1aac28fc016efefdeef4f
1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2013, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 /**
8 * \file sandbox.c
9 * \brief Code to enable sandboxing.
10 **/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
16 #include "sandbox.h"
17 #include "torlog.h"
18 #include "orconfig.h"
20 #if defined(HAVE_SECCOMP_H) && defined(__linux__)
21 #define USE_LIBSECCOMP
22 #endif
24 #define DEBUGGING_CLOSE
26 #if defined(USE_LIBSECCOMP)
28 #include <sys/syscall.h>
29 #include <seccomp.h>
30 #include <signal.h>
31 #include <unistd.h>
33 /** Variable used for storing all syscall numbers that will be allowed with the
34 * stage 1 general Tor sandbox.
36 static int general_filter[] = {
37 SCMP_SYS(access),
38 SCMP_SYS(brk),
39 SCMP_SYS(clock_gettime),
40 SCMP_SYS(close),
41 SCMP_SYS(clone),
42 SCMP_SYS(epoll_create),
43 SCMP_SYS(epoll_ctl),
44 SCMP_SYS(epoll_wait),
45 SCMP_SYS(execve),
46 SCMP_SYS(fcntl),
47 #ifdef __NR_fcntl64
48 /* Older libseccomp versions don't define PNR entries for all of these,
49 * so we need to ifdef them here.*/
50 SCMP_SYS(fcntl64),
51 #endif
52 SCMP_SYS(flock),
53 SCMP_SYS(fstat),
54 #ifdef __NR_fstat64
55 SCMP_SYS(fstat64),
56 #endif
57 SCMP_SYS(futex),
58 SCMP_SYS(getdents64),
59 SCMP_SYS(getegid),
60 #ifdef __NR_getegid32
61 SCMP_SYS(getegid32),
62 #endif
63 SCMP_SYS(geteuid),
64 #ifdef __NR_geteuid32
65 SCMP_SYS(geteuid32),
66 #endif
67 SCMP_SYS(getgid),
68 #ifdef __NR_getgid32
69 SCMP_SYS(getgid32),
70 #endif
71 SCMP_SYS(getrlimit),
72 SCMP_SYS(gettimeofday),
73 SCMP_SYS(getuid),
74 #ifdef __NR_getuid32
75 SCMP_SYS(getuid32),
76 #endif
77 SCMP_SYS(lseek),
78 #ifdef __NR__llseek
79 SCMP_SYS(_llseek),
80 #endif
81 SCMP_SYS(mkdir),
82 SCMP_SYS(mlockall),
83 SCMP_SYS(mmap),
84 #ifdef __NR_mmap2
85 SCMP_SYS(mmap2),
86 #endif
87 SCMP_SYS(mprotect),
88 SCMP_SYS(mremap),
89 SCMP_SYS(munmap),
90 SCMP_SYS(open),
91 SCMP_SYS(openat),
92 SCMP_SYS(poll),
93 SCMP_SYS(prctl),
94 SCMP_SYS(read),
95 SCMP_SYS(rename),
96 SCMP_SYS(rt_sigaction),
97 SCMP_SYS(rt_sigprocmask),
98 SCMP_SYS(rt_sigreturn),
99 #ifdef __NR_sigreturn
100 SCMP_SYS(sigreturn),
101 #endif
102 SCMP_SYS(set_robust_list),
103 SCMP_SYS(set_thread_area),
104 SCMP_SYS(set_tid_address),
105 SCMP_SYS(stat),
106 #ifdef __NR_stat64
107 SCMP_SYS(stat64),
108 #endif
109 SCMP_SYS(time),
110 SCMP_SYS(uname),
111 SCMP_SYS(write),
112 SCMP_SYS(exit_group),
113 SCMP_SYS(exit),
115 // socket syscalls
116 SCMP_SYS(accept4),
117 SCMP_SYS(bind),
118 SCMP_SYS(connect),
119 SCMP_SYS(getsockname),
120 SCMP_SYS(getsockopt),
121 SCMP_SYS(listen),
122 #if __NR_recv >= 0
123 /* This is a kludge; It's necessary on 64-bit with libseccomp 1.0.0; I
124 * don't know if other 64-bit or other versions require it. */
125 SCMP_SYS(recv),
126 #endif
127 SCMP_SYS(recvmsg),
128 #if __NR_send >= 0
129 SCMP_SYS(send),
130 #endif
131 SCMP_SYS(sendto),
132 SCMP_SYS(setsockopt),
133 SCMP_SYS(socket),
134 SCMP_SYS(socketpair),
136 // TODO: remove when accept4 is fixed
137 #ifdef __NR_socketcall
138 SCMP_SYS(socketcall),
139 #endif
141 SCMP_SYS(recvfrom),
142 SCMP_SYS(unlink)
146 * Function responsible for setting up and enabling a global syscall filter.
147 * The function is a prototype developed for stage 1 of sandboxing Tor.
148 * Returns 0 on success.
150 static int
151 install_glob_syscall_filter(void)
153 int rc = 0, i, filter_size;
154 scmp_filter_ctx ctx;
156 ctx = seccomp_init(SCMP_ACT_TRAP);
157 if (ctx == NULL) {
158 log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context");
159 rc = -1;
160 goto end;
163 if (general_filter != NULL) {
164 filter_size = sizeof(general_filter) / sizeof(general_filter[0]);
165 } else {
166 filter_size = 0;
169 // add general filters
170 for (i = 0; i < filter_size; i++) {
171 rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, general_filter[i], 0);
172 if (rc != 0) {
173 log_err(LD_BUG,"(Sandbox) failed to add syscall index %d, "
174 "received libseccomp error %d", i, rc);
175 goto end;
179 rc = seccomp_load(ctx);
181 end:
182 seccomp_release(ctx);
183 return (rc < 0 ? -rc : rc);
186 /** Additional file descriptor to use when logging seccomp2 failures */
187 static int sigsys_debugging_fd = -1;
189 /** Use the file descriptor <b>fd</b> to log seccomp2 failures. */
190 static void
191 sigsys_set_debugging_fd(int fd)
193 sigsys_debugging_fd = fd;
197 * Function called when a SIGSYS is caught by the application. It notifies the
198 * user that an error has occurred and either terminates or allows the
199 * application to continue execution, based on the DEBUGGING_CLOSE symbol.
201 static void
202 sigsys_debugging(int nr, siginfo_t *info, void *void_context)
204 ucontext_t *ctx = (ucontext_t *) (void_context);
205 char message[64];
206 int rv = 0, syscall, length, err;
207 (void) nr;
209 if (info->si_code != SYS_SECCOMP)
210 return;
212 if (!ctx)
213 return;
215 syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
217 /* XXXX Avoid use of snprintf; it isn't on the list of Stuff You're Allowed
218 * To Do In A Signal Handler. */
219 length = snprintf(message, sizeof(message),
220 "\n\n(Sandbox) bad syscall (%d) was caught.\n",
221 syscall);
223 err = 0;
224 if (sigsys_debugging_fd >= 0) {
225 rv = write(sigsys_debugging_fd, message, length);
226 err += rv != length;
229 rv = write(STDOUT_FILENO, message, length);
230 err += rv != length;
232 if (err)
233 _exit(2);
235 #if defined(DEBUGGING_CLOSE)
236 _exit(1);
237 #endif // DEBUGGING_CLOSE
241 * Function that adds a handler for SIGSYS, which is the signal thrown
242 * when the application is issuing a syscall which is not allowed. The
243 * main purpose of this function is to help with debugging by identifying
244 * filtered syscalls.
246 static int
247 install_sigsys_debugging(void)
249 struct sigaction act;
250 sigset_t mask;
252 memset(&act, 0, sizeof(act));
253 sigemptyset(&mask);
254 sigaddset(&mask, SIGSYS);
256 act.sa_sigaction = &sigsys_debugging;
257 act.sa_flags = SA_SIGINFO;
258 if (sigaction(SIGSYS, &act, NULL) < 0) {
259 log_err(LD_BUG,"(Sandbox) Failed to register SIGSYS signal handler");
260 return -1;
263 if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
264 log_err(LD_BUG,"(Sandbox) Failed call to sigprocmask()");
265 return -2;
268 return 0;
270 #endif // USE_LIBSECCOMP
272 #ifdef USE_LIBSECCOMP
274 * Initialises the syscall sandbox filter for any linux architecture, taking
275 * into account various available features for different linux flavours.
277 static int
278 initialise_libseccomp_sandbox(void)
280 if (install_sigsys_debugging())
281 return -1;
283 if (install_glob_syscall_filter())
284 return -2;
286 return 0;
289 #endif // USE_LIBSECCOMP
292 * Enables the stage 1 general sandbox. It applies a syscall filter which does
293 * not restrict any Tor features. The filter is representative for the whole
294 * application.
297 tor_global_sandbox(void)
300 #if defined(USE_LIBSECCOMP)
301 return initialise_libseccomp_sandbox();
303 #elif defined(_WIN32)
304 log_warn(LD_BUG,"Windows sandboxing is not implemented. The feature is "
305 "currently disabled.");
306 return 0;
308 #elif defined(TARGET_OS_MAC)
309 log_warn(LD_BUG,"Mac OSX sandboxing is not implemented. The feature is "
310 "currently disabled");
311 return 0;
312 #else
313 log_warn(LD_BUG,"Sandboxing is not implemented for your platform. The "
314 "feature is currently disabled");
315 return 0;
316 #endif
319 /** Use <b>fd</b> to log non-survivable sandbox violations. */
320 void
321 sandbox_set_debugging_fd(int fd)
323 #ifdef USE_LIBSECCOMP
324 sigsys_set_debugging_fd(fd);
325 #else
326 (void)fd;
327 #endif