sandbox.c 45.3 KB
Newer Older
1
/* Copyright (c) 2001 Matej Pfajfar.
2
3
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4
 * Copyright (c) 2007-2020, The Tor Project, Inc. */
5
6
7
8
9
10
11
/* See LICENSE for licensing information */

/**
 * \file sandbox.c
 * \brief Code to enable sandboxing.
 **/

12
13
14
#include "orconfig.h"

#ifndef _LARGEFILE64_SOURCE
Cristian Toader's avatar
Cristian Toader committed
15
16
17
18
/**
 * Temporarily required for O_LARGEFILE flag. Needs to be removed
 * with the libevent fix.
 */
Cristian Toader's avatar
Cristian Toader committed
19
#define _LARGEFILE64_SOURCE
20
#endif /* !defined(_LARGEFILE64_SOURCE) */
Cristian Toader's avatar
Cristian Toader committed
21

22
23
24
25
26
27
28
29
/** Malloc mprotect limit in bytes.
 *
 * 28/06/2017: This value was increased from 16 MB to 20 MB after we introduced
 * LZMA support in Tor (0.3.1.1-alpha). We limit our LZMA coder to 16 MB, but
 * liblzma have a small overhead that we need to compensate for to avoid being
 * killed by the sandbox.
 */
#define MALLOC_MP_LIM (20*1024*1024)
30

31
32
33
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
34
#include <errno.h>
35

36
#include "lib/sandbox/sandbox.h"
Nick Mathewson's avatar
Nick Mathewson committed
37
#include "lib/container/map.h"
38
#include "lib/err/torerr.h"
39
#include "lib/log/log.h"
40
#include "lib/cc/torint.h"
Nick Mathewson's avatar
Nick Mathewson committed
41
#include "lib/malloc/malloc.h"
42
#include "lib/string/scanf.h"
43

44
45
46
#include "ext/tor_queue.h"
#include "ext/ht.h"
#include "ext/siphash.h"
Nick Mathewson's avatar
Nick Mathewson committed
47

48
49
50
51
#define DEBUGGING_CLOSE

#if defined(USE_LIBSECCOMP)

52
#include <sys/mman.h>
53
#include <sys/syscall.h>
54
#include <sys/types.h>
Cristian Toader's avatar
Cristian Toader committed
55
#include <sys/stat.h>
Cristian Toader's avatar
Cristian Toader committed
56
#include <sys/epoll.h>
57
58
#include <sys/prctl.h>
#include <linux/futex.h>
59
#include <sys/file.h>
60

61
#include <stdarg.h>
62
63
64
#include <seccomp.h>
#include <signal.h>
#include <unistd.h>
65
#include <fcntl.h>
66
#include <time.h>
67
#include <poll.h>
68

69
70
71
#ifdef HAVE_GNU_LIBC_VERSION_H
#include <gnu/libc-version.h>
#endif
72
73
74
75
76
77
78
79
80
81
#ifdef HAVE_LINUX_NETFILTER_IPV4_H
#include <linux/netfilter_ipv4.h>
#endif
#ifdef HAVE_LINUX_IF_H
#include <linux/if.h>
#endif
#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
#include <linux/netfilter_ipv6/ip6_tables.h>
#endif

82
83
84
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
  defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
#define USE_BACKTRACE
teor's avatar
teor committed
85
#define BACKTRACE_PRIVATE
86
#include "lib/err/backtrace.h"
87
#endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */
88
89
90
91
92

#ifdef USE_BACKTRACE
#include <execinfo.h>
#endif

Nick Mathewson's avatar
Nick Mathewson committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
 * Linux 32 bit definitions
 */
#if defined(__i386__)

#define REG_SYSCALL REG_EAX
#define M_SYSCALL gregs[REG_SYSCALL]

/**
 * Linux 64 bit definitions
 */
#elif defined(__x86_64__)

#define REG_SYSCALL REG_RAX
#define M_SYSCALL gregs[REG_SYSCALL]

#elif defined(__arm__)

#define M_SYSCALL arm_r7

113
114
115
116
117
#elif defined(__aarch64__) && defined(__LP64__)

#define REG_SYSCALL 8
#define M_SYSCALL regs[REG_SYSCALL]

118
#endif /* defined(__i386__) || ... */
Nick Mathewson's avatar
Nick Mathewson committed
119

120
121
122
123
#ifdef M_SYSCALL
#define SYSCALL_NAME_DEBUGGING
#endif

124
/**Determines if at least one sandbox is active.*/
125
static int sandbox_active = 0;
126
/** Holds the parameter list configuration for the sandbox.*/
Cristian Toader's avatar
Cristian Toader committed
127
static sandbox_cfg_t *filter_dynamic = NULL;
128

129
130
#undef SCMP_CMP
#define SCMP_CMP(a,b,c) ((struct scmp_arg_cmp){(a),(b),(c),0})
131
#define SCMP_CMP_STR(a,b,c) \
Nick Mathewson's avatar
Nick Mathewson committed
132
  ((struct scmp_arg_cmp) {(a),(b),(intptr_t)(void*)(c),0})
133
134
135
136
137
138
139
#define SCMP_CMP4(a,b,c,d) ((struct scmp_arg_cmp){(a),(b),(c),(d)})
/* We use a wrapper here because these masked comparisons seem to be pretty
 * verbose. Also, it's important to cast to scmp_datum_t before negating the
 * mask, since otherwise the negation might get applied to a 32 bit value, and
 * the high bits of the value might get masked out improperly. */
#define SCMP_CMP_MASKED(a,b,c) \
  SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c))
140
141
142
143
/* For negative constants, the rule to add depends on the glibc version. */
#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \
                              (SCMP_CMP((a), (op), (unsigned int)(b))) : \
                              (SCMP_CMP_STR((a), (op), (b))))
144

145
146
147
/** Variable used for storing all syscall numbers that will be allowed with the
 * stage 1 general Tor sandbox.
 */
148
static int filter_nopar_gen[] = {
149
    SCMP_SYS(access),
150
    SCMP_SYS(brk),
Cristian Toader's avatar
Cristian Toader committed
151
    SCMP_SYS(clock_gettime),
152
153
    SCMP_SYS(close),
    SCMP_SYS(clone),
154
    SCMP_SYS(dup),
155
156
    SCMP_SYS(epoll_create),
    SCMP_SYS(epoll_wait),
157
158
159
#ifdef __NR_epoll_pwait
    SCMP_SYS(epoll_pwait),
#endif
Nick Mathewson's avatar
Nick Mathewson committed
160
#ifdef HAVE_EVENTFD
161
    SCMP_SYS(eventfd2),
Nick Mathewson's avatar
Nick Mathewson committed
162
163
164
165
166
167
#endif
#ifdef HAVE_PIPE2
    SCMP_SYS(pipe2),
#endif
#ifdef HAVE_PIPE
    SCMP_SYS(pipe),
168
169
170
#endif
#ifdef __NR_fchmod
    SCMP_SYS(fchmod),
Nick Mathewson's avatar
Nick Mathewson committed
171
#endif
172
173
174
175
176
    SCMP_SYS(fcntl),
    SCMP_SYS(fstat),
#ifdef __NR_fstat64
    SCMP_SYS(fstat64),
#endif
177
    SCMP_SYS(fsync),
178
    SCMP_SYS(futex),
179
    SCMP_SYS(getdents),
180
181
182
183
184
185
186
187
188
189
190
191
192
    SCMP_SYS(getdents64),
    SCMP_SYS(getegid),
#ifdef __NR_getegid32
    SCMP_SYS(getegid32),
#endif
    SCMP_SYS(geteuid),
#ifdef __NR_geteuid32
    SCMP_SYS(geteuid32),
#endif
    SCMP_SYS(getgid),
#ifdef __NR_getgid32
    SCMP_SYS(getgid32),
#endif
193
    SCMP_SYS(getpid),
Nick Mathewson's avatar
Nick Mathewson committed
194
#ifdef __NR_getrlimit
195
    SCMP_SYS(getrlimit),
Nick Mathewson's avatar
Nick Mathewson committed
196
#endif
197
    SCMP_SYS(gettimeofday),
198
    SCMP_SYS(gettid),
199
200
201
202
203
204
205
206
207
208
    SCMP_SYS(getuid),
#ifdef __NR_getuid32
    SCMP_SYS(getuid32),
#endif
    SCMP_SYS(lseek),
#ifdef __NR__llseek
    SCMP_SYS(_llseek),
#endif
    SCMP_SYS(mkdir),
    SCMP_SYS(mlockall),
Nick Mathewson's avatar
Nick Mathewson committed
209
210
#ifdef __NR_mmap
    /* XXXX restrict this in the same ways as mmap2 */
211
    SCMP_SYS(mmap),
Nick Mathewson's avatar
Nick Mathewson committed
212
#endif
213
    SCMP_SYS(munmap),
214
215
216
#ifdef __NR_nanosleep
    SCMP_SYS(nanosleep),
#endif
217
218
219
220
221
222
#ifdef __NR_prlimit
    SCMP_SYS(prlimit),
#endif
#ifdef __NR_prlimit64
    SCMP_SYS(prlimit64),
#endif
223
224
    SCMP_SYS(read),
    SCMP_SYS(rt_sigreturn),
225
    SCMP_SYS(sched_getaffinity),
226
227
228
#ifdef __NR_sched_yield
    SCMP_SYS(sched_yield),
#endif
229
    SCMP_SYS(sendmsg),
230
    SCMP_SYS(set_robust_list),
231
232
233
#ifdef __NR_setrlimit
    SCMP_SYS(setrlimit),
#endif
234
    SCMP_SYS(shutdown),
235
236
237
#ifdef __NR_sigaltstack
    SCMP_SYS(sigaltstack),
#endif
238
239
240
241
#ifdef __NR_sigreturn
    SCMP_SYS(sigreturn),
#endif
    SCMP_SYS(stat),
242
    SCMP_SYS(uname),
243
    SCMP_SYS(wait4),
244
    SCMP_SYS(write),
245
    SCMP_SYS(writev),
246
247
248
    SCMP_SYS(exit_group),
    SCMP_SYS(exit),

249
    SCMP_SYS(madvise),
Nick Mathewson's avatar
Nick Mathewson committed
250
#ifdef __NR_stat64
251
252
    // getaddrinfo uses this..
    SCMP_SYS(stat64),
Nick Mathewson's avatar
Nick Mathewson committed
253
#endif
254

255
256
257
258
#ifdef __NR_getrandom
    SCMP_SYS(getrandom),
#endif

259
260
261
262
#ifdef __NR_sysinfo
    // qsort uses this..
    SCMP_SYS(sysinfo),
#endif
263
264
265
266
267
268
269
270
271
    /*
     * These socket syscalls are not required on x86_64 and not supported with
     * some libseccomp versions (eg: 1.0.1)
     */
#if defined(__i386)
    SCMP_SYS(recv),
    SCMP_SYS(send),
#endif

272
273
    // socket syscalls
    SCMP_SYS(bind),
Nick Mathewson's avatar
Nick Mathewson committed
274
    SCMP_SYS(listen),
275
276
    SCMP_SYS(connect),
    SCMP_SYS(getsockname),
277
278
279
280
281
#ifdef ENABLE_NSS
#ifdef __NR_getpeername
    SCMP_SYS(getpeername),
#endif
#endif
282
    SCMP_SYS(recvmsg),
Cristian Toader's avatar
Cristian Toader committed
283
    SCMP_SYS(recvfrom),
284
    SCMP_SYS(sendto),
285
    SCMP_SYS(unlink),
286
287
288
#ifdef __NR_unlinkat
    SCMP_SYS(unlinkat),
#endif
289
    SCMP_SYS(poll)
290
291
};

292
293
294
295
296
297
/* opendir is not a syscall but it will use either open or openat. We do not
 * want the decision to allow open/openat to be the callers reponsability, so
 * we create a phony syscall number for opendir and sb_opendir will choose the
 * correct syscall. */
#define PHONY_OPENDIR_SYSCALL -2

298
299
300
301
302
303
304
305
306
307
308
309
310
/* These macros help avoid the error where the number of filters we add on a
 * single rule don't match the arg_cnt param. */
#define seccomp_rule_add_0(ctx,act,call) \
  seccomp_rule_add((ctx),(act),(call),0)
#define seccomp_rule_add_1(ctx,act,call,f1) \
  seccomp_rule_add((ctx),(act),(call),1,(f1))
#define seccomp_rule_add_2(ctx,act,call,f1,f2)  \
  seccomp_rule_add((ctx),(act),(call),2,(f1),(f2))
#define seccomp_rule_add_3(ctx,act,call,f1,f2,f3)       \
  seccomp_rule_add((ctx),(act),(call),3,(f1),(f2),(f3))
#define seccomp_rule_add_4(ctx,act,call,f1,f2,f3,f4)      \
  seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4))

311
312
313
314
/**
 * Function responsible for setting up the rt_sigaction syscall for
 * the seccomp filter sandbox.
 */
315
static int
316
sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
317
{
318
319
  unsigned i;
  int rc;
320
  int param[] = { SIGINT, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGCHLD,
321
                  SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, SIGIO,
322
323
324
325
#ifdef SIGXFSZ
      SIGXFSZ
#endif
      };
326
  (void) filter;
327

Cristian Toader's avatar
Cristian Toader committed
328
  for (i = 0; i < ARRAY_LENGTH(param); i++) {
329
    rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction),
330
        SCMP_CMP(0, SCMP_CMP_EQ, param[i]));
Cristian Toader's avatar
Cristian Toader committed
331
    if (rc)
332
333
334
335
336
337
      break;
  }

  return rc;
}

338
339
340
341
/**
 * Function responsible for setting up the time syscall for
 * the seccomp filter sandbox.
 */
342
static int
343
sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
344
{
345
  (void) filter;
Nick Mathewson's avatar
Nick Mathewson committed
346
#ifdef __NR_time
347
  return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time),
348
       SCMP_CMP(0, SCMP_CMP_EQ, 0));
Nick Mathewson's avatar
Nick Mathewson committed
349
350
#else
  return 0;
351
#endif /* defined(__NR_time) */
352
353
}

354
355
356
357
/**
 * Function responsible for setting up the accept4 syscall for
 * the seccomp filter sandbox.
 */
358
static int
359
sb_accept4(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
360
{
Cristian Toader's avatar
Cristian Toader committed
361
  int rc = 0;
362
  (void)filter;
Cristian Toader's avatar
Cristian Toader committed
363
364

#ifdef __i386__
365
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall),
Cristian Toader's avatar
Cristian Toader committed
366
      SCMP_CMP(0, SCMP_CMP_EQ, 18));
Cristian Toader's avatar
Cristian Toader committed
367
368
369
  if (rc) {
    return rc;
  }
370
#endif /* defined(__i386__) */
Cristian Toader's avatar
Cristian Toader committed
371

372
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4),
373
                   SCMP_CMP_MASKED(3, SOCK_CLOEXEC|SOCK_NONBLOCK, 0));
374
375
376
  if (rc) {
    return rc;
  }
Cristian Toader's avatar
Cristian Toader committed
377
378

  return 0;
379
380
381
}

#ifdef __NR_mmap2
382
383
384
385
/**
 * Function responsible for setting up the mmap2 syscall for
 * the seccomp filter sandbox.
 */
386
static int
387
sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
388
{
389
  int rc = 0;
Nick Mathewson's avatar
Nick Mathewson committed
390
  (void)filter;
391

392
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
393
394
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE));
Cristian Toader's avatar
Cristian Toader committed
395
  if (rc) {
396
    return rc;
397
398
  }

399
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
400
401
402
403
404
405
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE));
  if (rc) {
    return rc;
  }

406
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
407
408
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS));
Cristian Toader's avatar
Cristian Toader committed
409
  if (rc) {
410
411
412
    return rc;
  }

413
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
414
415
416
417
418
419
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
       SCMP_CMP(3, SCMP_CMP_EQ,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK));
  if (rc) {
    return rc;
  }

420
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
421
422
423
424
425
426
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE));
  if (rc) {
    return rc;
  }

427
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
428
429
430
431
432
433
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS));
  if (rc) {
    return rc;
  }

434
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
435
436
437
438
439
440
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_EXEC),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_DENYWRITE));
  if (rc) {
    return rc;
  }

441
442
  return 0;
}
443
#endif /* defined(__NR_mmap2) */
444

445
446
447
448
449
450
#ifdef HAVE_GNU_LIBC_VERSION_H
#ifdef HAVE_GNU_GET_LIBC_VERSION
#define CHECK_LIBC_VERSION
#endif
#endif

451
452
/* Return true the libc version is greater or equal than
 * <b>major</b>.<b>minor</b>. Returns false otherwise. */
453
static int
454
is_libc_at_least(int major, int minor)
455
456
457
458
459
460
{
#ifdef CHECK_LIBC_VERSION
  const char *version = gnu_get_libc_version();
  if (version == NULL)
    return 0;

461
462
  int libc_major = -1;
  int libc_minor = -1;
463

464
465
  tor_sscanf(version, "%d.%d", &libc_major, &libc_minor);
  if (libc_major > major)
466
    return 1;
467
  else if (libc_major == major && libc_minor >= minor)
468
469
470
    return 1;
  else
    return 0;
471
#else /* !defined(CHECK_LIBC_VERSION) */
472
473
  (void)major;
  (void)minor;
474
  return 0;
475
#endif /* defined(CHECK_LIBC_VERSION) */
476
477
}

478
479
/* Return true if we think we're running with a libc that uses openat for the
 * open function on linux. */
480
static int
481
libc_uses_openat_for_open(void)
482
483
484
485
{
  return is_libc_at_least(2, 26);
}

486
487
488
489
490
491
492
493
494
495
/* Return true if we think we're running with a libc that uses openat for the
 * opendir function on linux. */
static int
libc_uses_openat_for_opendir(void)
{
  // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive)
  return is_libc_at_least(2, 27) ||
         (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22));
}

496
497
498
499
500
501
502
503
/* Return true if we think we're running with a libc that needs to cast
 * negative arguments like AT_FDCWD for seccomp rules. */
static int
libc_negative_constant_needs_cast(void)
{
  return is_libc_at_least(2, 27);
}

504
505
506
507
508
509
510
/** Allow a single file to be opened.  If <b>use_openat</b> is true,
 * we're using a libc that remaps all the opens into openats. */
static int
allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file)
{
  if (use_openat) {
    return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
511
                              SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
512
513
514
515
516
517
518
                              SCMP_CMP_STR(1, SCMP_CMP_EQ, file));
  } else {
    return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
                              SCMP_CMP_STR(0, SCMP_CMP_EQ, file));
  }
}

519
520
521
522
/**
 * Function responsible for setting up the open syscall for
 * the seccomp filter sandbox.
 */
523
static int
524
sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
525
{
526
  int rc;
527
  sandbox_cfg_t *elem = NULL;
528

529
  int use_openat = libc_uses_openat_for_open();
530

531
  // for each dynamic parameter filters
532
  for (elem = filter; elem != NULL; elem = elem->next) {
533
534
535
536
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(open)) {
537
      rc = allow_file_open(ctx, use_openat, param->value);
538
      if (rc != 0) {
Cristian Toader's avatar
Cristian Toader committed
539
540
        log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
            "libseccomp error %d", rc);
541
542
        return rc;
      }
543
544
545
    }
  }

546
547
548
  return 0;
}

549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
static int
sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc;
  sandbox_cfg_t *elem = NULL;

  // for each dynamic parameter filters
  for (elem = filter; elem != NULL; elem = elem->next) {
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(chmod)) {
      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chmod),
            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
      if (rc != 0) {
564
        log_err(LD_BUG,"(Sandbox) failed to add chmod syscall, received "
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
            "libseccomp error %d", rc);
        return rc;
      }
    }
  }

  return 0;
}

static int
sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc;
  sandbox_cfg_t *elem = NULL;

  // for each dynamic parameter filters
  for (elem = filter; elem != NULL; elem = elem->next) {
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(chown)) {
      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown),
            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
      if (rc != 0) {
589
        log_err(LD_BUG,"(Sandbox) failed to add chown syscall, received "
590
591
592
593
594
595
596
597
598
            "libseccomp error %d", rc);
        return rc;
      }
    }
  }

  return 0;
}

599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
/**
 * Function responsible for setting up the rename syscall for
 * the seccomp filter sandbox.
 */
static int
sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc;
  sandbox_cfg_t *elem = NULL;

  // for each dynamic parameter filters
  for (elem = filter; elem != NULL; elem = elem->next) {
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 &&
        param->syscall == SCMP_SYS(rename)) {

616
      rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename),
617
618
            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value),
            SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2));
619
620
621
622
623
624
625
626
627
628
629
      if (rc != 0) {
        log_err(LD_BUG,"(Sandbox) failed to add rename syscall, received "
            "libseccomp error %d", rc);
        return rc;
      }
    }
  }

  return 0;
}

630
631
632
633
/**
 * Function responsible for setting up the openat syscall for
 * the seccomp filter sandbox.
 */
634
static int
635
sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
636
{
637
  int rc;
638
  sandbox_cfg_t *elem = NULL;
639
640

  // for each dynamic parameter filters
641
  for (elem = filter; elem != NULL; elem = elem->next) {
642
643
644
645
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(openat)) {
646
      rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
647
          SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
648
          SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
Cristian Toader's avatar
Cristian Toader committed
649
650
          SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|
              O_CLOEXEC));
651
      if (rc != 0) {
652
653
        log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
            "libseccomp error %d", rc);
654
655
656
657
658
659
660
661
        return rc;
      }
    }
  }

  return 0;
}

662
663
664
665
666
667
668
669
670
671
672
673
static int
sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc;
  sandbox_cfg_t *elem = NULL;

  // for each dynamic parameter filters
  for (elem = filter; elem != NULL; elem = elem->next) {
    smp_param_t *param = elem->param;

    if (param != NULL && param->prot == 1 && param->syscall
        == PHONY_OPENDIR_SYSCALL) {
674
      rc = allow_file_open(ctx, libc_uses_openat_for_opendir(), param->value);
675
676
677
678
679
680
681
682
683
684
685
      if (rc != 0) {
        log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
            "libseccomp error %d", rc);
        return rc;
      }
    }
  }

  return 0;
}

686
687
688
689
/**
 * Function responsible for setting up the socket syscall for
 * the seccomp filter sandbox.
 */
690
static int
691
sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
692
693
{
  int rc = 0;
694
  int i, j;
695
  (void) filter;
696

Cristian Toader's avatar
Cristian Toader committed
697
#ifdef __i386__
698
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket));
Cristian Toader's avatar
Cristian Toader committed
699
700
701
702
  if (rc)
    return rc;
#endif

703
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
Cristian Toader's avatar
Cristian Toader committed
704
      SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
705
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM));
Cristian Toader's avatar
Cristian Toader committed
706
707
708
  if (rc)
    return rc;

709
710
  for (i = 0; i < 2; ++i) {
    const int pf = i ? PF_INET : PF_INET6;
711
712
713
714
715
716
717
718
719
720
721
722
723
    for (j=0; j < 3; ++j) {
      const int type     = (j == 0) ? SOCK_STREAM :
                                      SOCK_DGRAM;
      const int protocol = (j == 0) ? IPPROTO_TCP :
                           (j == 1) ? IPPROTO_IP :
                                      IPPROTO_UDP;
      rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
        SCMP_CMP(0, SCMP_CMP_EQ, pf),
        SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, type),
        SCMP_CMP(2, SCMP_CMP_EQ, protocol));
      if (rc)
        return rc;
    }
724
  }
Cristian Toader's avatar
Cristian Toader committed
725

726
727
728
729
730
731
732
733
734
#ifdef ENABLE_NSS
  rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
    SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
    SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM),
    SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
  if (rc)
    return rc;
#endif

735
736
737
738
  rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
      SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM),
      SCMP_CMP(2, SCMP_CMP_EQ, 0));
739
740
741
742
743
744
745
746
747
  if (rc)
    return rc;

  rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
      SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_DGRAM),
      SCMP_CMP(2, SCMP_CMP_EQ, 0));
  if (rc)
    return rc;
748

749
  rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
750
      SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
751
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC, SOCK_RAW),
752
      SCMP_CMP(2, SCMP_CMP_EQ, 0));
753
754
755
756
757
758
  if (rc)
    return rc;

  return 0;
}

759
760
761
762
/**
 * Function responsible for setting up the socketpair syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
Cristian Toader committed
763
764
765
766
static int
sb_socketpair(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
767
  (void) filter;
Cristian Toader's avatar
Cristian Toader committed
768
769

#ifdef __i386__
770
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair));
Cristian Toader's avatar
Cristian Toader committed
771
772
773
774
  if (rc)
    return rc;
#endif

775
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair),
Cristian Toader's avatar
Cristian Toader committed
776
777
778
779
780
781
782
783
      SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC));
  if (rc)
    return rc;

  return 0;
}

784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
#ifdef HAVE_KIST_SUPPORT

#include <linux/sockios.h>

static int
sb_ioctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc;
  (void) filter;

  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl),
                          SCMP_CMP(1, SCMP_CMP_EQ, SIOCOUTQNSD));
  if (rc)
    return rc;
  return 0;
}

801
#endif /* defined(HAVE_KIST_SUPPORT) */
802

803
804
805
806
/**
 * Function responsible for setting up the setsockopt syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
807
static int
808
sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
809
810
{
  int rc = 0;
811
  (void) filter;
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
812

Cristian Toader's avatar
Cristian Toader committed
813
#ifdef __i386__
814
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt));
Cristian Toader's avatar
Cristian Toader committed
815
816
817
818
  if (rc)
    return rc;
#endif

819
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
820
821
822
823
824
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_REUSEADDR));
  if (rc)
    return rc;

825
826
827
828
829
830
831
832
833
834
835
836
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF));
  if (rc)
    return rc;

  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_RCVBUF));
  if (rc)
    return rc;

837
838
839
840
841
842
#ifdef HAVE_SYSTEMD
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUFFORCE));
  if (rc)
    return rc;
843
#endif /* defined(HAVE_SYSTEMD) */
844

845
#ifdef IP_TRANSPARENT
846
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
847
848
849
850
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
      SCMP_CMP(2, SCMP_CMP_EQ, IP_TRANSPARENT));
  if (rc)
    return rc;
851
#endif /* defined(IP_TRANSPARENT) */
852

853
854
855
856
857
858
#ifdef IPV6_V6ONLY
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, IPPROTO_IPV6),
      SCMP_CMP(2, SCMP_CMP_EQ, IPV6_V6ONLY));
  if (rc)
    return rc;
859
#endif /* defined(IPV6_V6ONLY) */
860

Cristian Toader's avatar
fcntl64    
Cristian Toader committed
861
862
863
  return 0;
}

864
865
866
867
/**
 * Function responsible for setting up the getsockopt syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
Cristian Toader committed
868
869
static int
sb_getsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
Cristian Toader committed
870
871
{
  int rc = 0;
872
  (void) filter;
Cristian Toader's avatar
Cristian Toader committed
873
874

#ifdef __i386__
875
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt));
Cristian Toader's avatar
Cristian Toader committed
876
877
878
879
  if (rc)
    return rc;
#endif

880
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
Cristian Toader's avatar
Cristian Toader committed
881
882
883
884
885
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_ERROR));
  if (rc)
    return rc;

886
887
888
889
890
891
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_ACCEPTCONN));
  if (rc)
    return rc;

892
893
894
895
896
897
#ifdef HAVE_SYSTEMD
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF));
  if (rc)
    return rc;
898
#endif /* defined(HAVE_SYSTEMD) */
899

900
901
902
903
904
905
#ifdef HAVE_LINUX_NETFILTER_IPV4_H
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_ORIGINAL_DST));
  if (rc)
    return rc;
906
#endif /* defined(HAVE_LINUX_NETFILTER_IPV4_H) */
907
908
909
910
911
912
913

#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IPV6),
      SCMP_CMP(2, SCMP_CMP_EQ, IP6T_SO_ORIGINAL_DST));
  if (rc)
    return rc;
914
#endif /* defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H) */
915

916
917
918
919
920
921
922
#ifdef HAVE_KIST_SUPPORT
#include <netinet/tcp.h>
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_TCP),
      SCMP_CMP(2, SCMP_CMP_EQ, TCP_INFO));
  if (rc)
    return rc;
923
#endif /* defined(HAVE_KIST_SUPPORT) */
924

Cristian Toader's avatar
Cristian Toader committed
925
926
927
  return 0;
}

Cristian Toader's avatar
fcntl64    
Cristian Toader committed
928
#ifdef __NR_fcntl64
929
930
931
932
/**
 * Function responsible for setting up the fcntl64 syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
933
static int
934
sb_fcntl64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
935
936
{
  int rc = 0;
Nick Mathewson's avatar
Nick Mathewson committed
937
  (void) filter;
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
938

939
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
940
941
942
943
      SCMP_CMP(1, SCMP_CMP_EQ, F_GETFL));
  if (rc)
    return rc;

944
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
945
946
947
948
949
      SCMP_CMP(1, SCMP_CMP_EQ, F_SETFL),
      SCMP_CMP(2, SCMP_CMP_EQ, O_RDWR|O_NONBLOCK));
  if (rc)
    return rc;

950
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
951
952
953
954
      SCMP_CMP(1, SCMP_CMP_EQ, F_GETFD));
  if (rc)
    return rc;

955
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
956
957
958
959
960
      SCMP_CMP(1, SCMP_CMP_EQ, F_SETFD),
      SCMP_CMP(2, SCMP_CMP_EQ, FD_CLOEXEC));
  if (rc)
    return rc;

Cristian Toader's avatar
fcntl64    
Cristian Toader committed
961
962
  return 0;
}
963
#endif /* defined(__NR_fcntl64) */
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
964

965
966
967
968
969
970
/**
 * Function responsible for setting up the epoll_ctl syscall for
 * the seccomp filter sandbox.
 *
 *  Note: basically allows everything but will keep for now..
 */
Cristian Toader's avatar
Cristian Toader committed
971
static int
972
sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
Cristian Toader committed
973
974
{
  int rc = 0;
975
  (void) filter;
Cristian Toader's avatar
Cristian Toader committed
976

977
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
Cristian Toader's avatar
Cristian Toader committed
978
979
980
981
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_ADD));
  if (rc)
    return rc;

982
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
Cristian Toader's avatar
Cristian Toader committed
983
984
985
986
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_MOD));
  if (rc)
    return rc;

987
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
Cristian Toader's avatar
Cristian Toader committed
988
989
990
991
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_DEL));
  if (rc)
    return rc;

Cristian Toader's avatar
Cristian Toader committed
992
993
994
  return 0;
}

995
/**
996
 * Function responsible for setting up the prctl syscall for
997
998
999
1000
 * the seccomp filter sandbox.
 *
 * NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs
 * to be whitelisted in this function.
For faster browsing, not all history is shown. View entire blame