sandbox.c 40 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* 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
Cristian Toader's avatar
Cristian Toader committed
21

22
23
24
/** Malloc mprotect limit in bytes. */
#define MALLOC_MP_LIM 1048576

25
26
27
28
29
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "sandbox.h"
30
#include "container.h"
31
#include "torlog.h"
32
#include "torint.h"
Cristian Toader's avatar
Cristian Toader committed
33
#include "util.h"
34
#include "tor_queue.h"
35

36
37
#include "ht.h"

38
39
40
41
#define DEBUGGING_CLOSE

#if defined(USE_LIBSECCOMP)

42
43
#define _GNU_SOURCE

44
#include <sys/mman.h>
45
#include <sys/syscall.h>
46
#include <sys/types.h>
Cristian Toader's avatar
Cristian Toader committed
47
#include <sys/stat.h>
Cristian Toader's avatar
Cristian Toader committed
48
#include <sys/epoll.h>
49
50
#include <sys/prctl.h>
#include <linux/futex.h>
51
#include <bits/signum.h>
52

53
#include <stdarg.h>
54
55
56
#include <seccomp.h>
#include <signal.h>
#include <unistd.h>
57
#include <fcntl.h>
58
#include <time.h>
59
#include <poll.h>
60

61
62
63
64
65
66
67
68
69
70
71
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
  defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
#define USE_BACKTRACE
#define EXPOSE_CLEAN_BACKTRACE
#include "backtrace.h"
#endif

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

Nick Mathewson's avatar
Nick Mathewson committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
 * 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

#endif

94
/**Determines if at least one sandbox is active.*/
95
static int sandbox_active = 0;
96
/** Holds the parameter list configuration for the sandbox.*/
Cristian Toader's avatar
Cristian Toader committed
97
static sandbox_cfg_t *filter_dynamic = NULL;
98

99
100
#undef SCMP_CMP
#define SCMP_CMP(a,b,c) ((struct scmp_arg_cmp){(a),(b),(c),0})
101
#define SCMP_CMP_STR(a,b,c) \
Nick Mathewson's avatar
Nick Mathewson committed
102
  ((struct scmp_arg_cmp) {(a),(b),(intptr_t)(void*)(c),0})
103
104
105
106
107
108
109
#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))
110

111
112
113
/** Variable used for storing all syscall numbers that will be allowed with the
 * stage 1 general Tor sandbox.
 */
114
static int filter_nopar_gen[] = {
115
    SCMP_SYS(access),
116
    SCMP_SYS(brk),
Cristian Toader's avatar
Cristian Toader committed
117
    SCMP_SYS(clock_gettime),
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    SCMP_SYS(close),
    SCMP_SYS(clone),
    SCMP_SYS(epoll_create),
    SCMP_SYS(epoll_wait),
    SCMP_SYS(fcntl),
    SCMP_SYS(fstat),
#ifdef __NR_fstat64
    SCMP_SYS(fstat64),
#endif
    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
Nick Mathewson's avatar
Nick Mathewson committed
140
#ifdef __NR_getrlimit
141
    SCMP_SYS(getrlimit),
Nick Mathewson's avatar
Nick Mathewson committed
142
#endif
143
    SCMP_SYS(gettimeofday),
144
    SCMP_SYS(gettid),
145
146
147
148
149
150
151
152
153
154
    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
155
156
#ifdef __NR_mmap
    /* XXXX restrict this in the same ways as mmap2 */
157
    SCMP_SYS(mmap),
Nick Mathewson's avatar
Nick Mathewson committed
158
#endif
159
160
161
    SCMP_SYS(munmap),
    SCMP_SYS(read),
    SCMP_SYS(rt_sigreturn),
162
    SCMP_SYS(sched_getaffinity),
163
    SCMP_SYS(set_robust_list),
164
165
166
167
#ifdef __NR_sigreturn
    SCMP_SYS(sigreturn),
#endif
    SCMP_SYS(stat),
168
    SCMP_SYS(uname),
169
    SCMP_SYS(write),
170
    SCMP_SYS(writev),
171
172
173
    SCMP_SYS(exit_group),
    SCMP_SYS(exit),

174
    SCMP_SYS(madvise),
Nick Mathewson's avatar
Nick Mathewson committed
175
#ifdef __NR_stat64
176
177
    // getaddrinfo uses this..
    SCMP_SYS(stat64),
Nick Mathewson's avatar
Nick Mathewson committed
178
#endif
179

180
181
182
183
184
185
186
187
188
    /*
     * 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

189
190
    // socket syscalls
    SCMP_SYS(bind),
Nick Mathewson's avatar
Nick Mathewson committed
191
    SCMP_SYS(listen),
192
193
194
    SCMP_SYS(connect),
    SCMP_SYS(getsockname),
    SCMP_SYS(recvmsg),
Cristian Toader's avatar
Cristian Toader committed
195
    SCMP_SYS(recvfrom),
196
    SCMP_SYS(sendto),
197
    SCMP_SYS(unlink)
198
199
};

200
201
202
203
204
205
206
207
208
209
210
211
212
/* 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))

213
214
215
216
/**
 * Function responsible for setting up the rt_sigaction syscall for
 * the seccomp filter sandbox.
 */
217
static int
218
sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
219
{
220
221
  unsigned i;
  int rc;
222
223
224
225
226
  int param[] = { SIGINT, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGCHLD,
#ifdef SIGXFSZ
      SIGXFSZ
#endif
      };
227
  (void) filter;
228

Cristian Toader's avatar
Cristian Toader committed
229
  for (i = 0; i < ARRAY_LENGTH(param); i++) {
230
    rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction),
231
        SCMP_CMP(0, SCMP_CMP_EQ, param[i]));
Cristian Toader's avatar
Cristian Toader committed
232
    if (rc)
233
234
235
236
237
238
      break;
  }

  return rc;
}

239
#if 0
240
241
242
243
/**
 * Function responsible for setting up the execve syscall for
 * the seccomp filter sandbox.
 */
244
static int
245
sb_execve(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
246
{
247
  int rc;
248
  sandbox_cfg_t *elem = NULL;
249

250
  // for each dynamic parameter filters
251
  for (elem = filter; elem != NULL; elem = elem->next) {
252
    smp_param_t *param = elem->param;
253
254
255

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(execve)) {
256
      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve),
257
               SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
258
      if (rc != 0) {
Cristian Toader's avatar
Cristian Toader committed
259
260
        log_err(LD_BUG,"(Sandbox) failed to add execve syscall, received "
            "libseccomp error %d", rc);
261
262
263
264
        return rc;
      }
    }
  }
265

266
267
  return 0;
}
268
#endif
269

270
271
272
273
/**
 * Function responsible for setting up the time syscall for
 * the seccomp filter sandbox.
 */
274
static int
275
sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
276
{
277
  (void) filter;
Nick Mathewson's avatar
Nick Mathewson committed
278
#ifdef __NR_time
279
  return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time),
280
       SCMP_CMP(0, SCMP_CMP_EQ, 0));
Nick Mathewson's avatar
Nick Mathewson committed
281
282
283
#else
  return 0;
#endif
284
285
}

286
287
288
289
/**
 * Function responsible for setting up the accept4 syscall for
 * the seccomp filter sandbox.
 */
290
static int
291
sb_accept4(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
292
{
Cristian Toader's avatar
Cristian Toader committed
293
  int rc = 0;
294
  (void)filter;
Cristian Toader's avatar
Cristian Toader committed
295
296

#ifdef __i386__
297
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall),
Cristian Toader's avatar
Cristian Toader committed
298
      SCMP_CMP(0, SCMP_CMP_EQ, 18));
Cristian Toader's avatar
Cristian Toader committed
299
300
301
302
303
  if (rc) {
    return rc;
  }
#endif

304
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4),
305
                   SCMP_CMP_MASKED(3, SOCK_CLOEXEC|SOCK_NONBLOCK, 0));
306
307
308
  if (rc) {
    return rc;
  }
Cristian Toader's avatar
Cristian Toader committed
309
310

  return 0;
311
312
313
}

#ifdef __NR_mmap2
314
315
316
317
/**
 * Function responsible for setting up the mmap2 syscall for
 * the seccomp filter sandbox.
 */
318
static int
319
sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
320
{
321
  int rc = 0;
Nick Mathewson's avatar
Nick Mathewson committed
322
  (void)filter;
323

324
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
325
326
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE));
Cristian Toader's avatar
Cristian Toader committed
327
  if (rc) {
328
    return rc;
329
330
  }

331
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
332
333
334
335
336
337
       SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE),
       SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE));
  if (rc) {
    return rc;
  }

338
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
339
340
       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
341
  if (rc) {
342
343
344
    return rc;
  }

345
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
346
347
348
349
350
351
       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;
  }

352
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
353
354
355
356
357
358
      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;
  }

359
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
360
361
362
363
364
365
      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;
  }

366
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2),
367
368
369
370
371
372
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_EXEC),
      SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_DENYWRITE));
  if (rc) {
    return rc;
  }

373
374
375
376
  return 0;
}
#endif

377
378
379
380
/**
 * Function responsible for setting up the open syscall for
 * the seccomp filter sandbox.
 */
381
static int
382
sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
383
{
384
  int rc;
385
  sandbox_cfg_t *elem = NULL;
386
387

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

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(open)) {
393
      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
394
            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
395
      if (rc != 0) {
Cristian Toader's avatar
Cristian Toader committed
396
397
        log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
            "libseccomp error %d", rc);
398
399
        return rc;
      }
400
401
402
    }
  }

403
404
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open),
                SCMP_CMP_MASKED(1, O_CLOEXEC|O_NONBLOCK|O_NOCTTY, O_RDONLY));
405
406
407
408
409
  if (rc != 0) {
    log_err(LD_BUG,"(Sandbox) failed to add open syscall, received libseccomp "
        "error %d", rc);
    return rc;
  }
410

411
412
413
  return 0;
}

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
static int
sb__sysctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc;
  (void) filter;
  (void) ctx;

  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(_sysctl));
  if (rc != 0) {
    log_err(LD_BUG,"(Sandbox) failed to add _sysctl syscall, "
        "received libseccomp error %d", rc);
    return rc;
  }

  return 0;
}

431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
/**
 * 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)) {

448
      rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename),
449
450
            SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value),
            SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2));
451
452
453
454
455
456
457
458
459
460
461
      if (rc != 0) {
        log_err(LD_BUG,"(Sandbox) failed to add rename syscall, received "
            "libseccomp error %d", rc);
        return rc;
      }
    }
  }

  return 0;
}

462
463
464
465
/**
 * Function responsible for setting up the openat syscall for
 * the seccomp filter sandbox.
 */
466
static int
467
sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
468
{
469
  int rc;
470
  sandbox_cfg_t *elem = NULL;
471
472

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

    if (param != NULL && param->prot == 1 && param->syscall
        == SCMP_SYS(openat)) {
478
      rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
Cristian Toader's avatar
Cristian Toader committed
479
          SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD),
480
          SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
Cristian Toader's avatar
Cristian Toader committed
481
482
          SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|
              O_CLOEXEC));
483
      if (rc != 0) {
484
485
        log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
            "libseccomp error %d", rc);
486
487
488
489
490
491
492
493
        return rc;
      }
    }
  }

  return 0;
}

494
495
496
497
/**
 * Function responsible for setting up the socket syscall for
 * the seccomp filter sandbox.
 */
498
static int
499
sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
500
501
{
  int rc = 0;
502
  int i;
503
  (void) filter;
504

Cristian Toader's avatar
Cristian Toader committed
505
#ifdef __i386__
506
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket));
Cristian Toader's avatar
Cristian Toader committed
507
508
509
510
  if (rc)
    return rc;
#endif

511
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
Cristian Toader's avatar
Cristian Toader committed
512
      SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
513
      SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM));
Cristian Toader's avatar
Cristian Toader committed
514
515
516
  if (rc)
    return rc;

517
518
  for (i = 0; i < 2; ++i) {
    const int pf = i ? PF_INET : PF_INET6;
519

520
521
522
    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, SOCK_STREAM),
Nick Mathewson's avatar
Nick Mathewson committed
523
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_TCP));
524
525
    if (rc)
      return rc;
Nick Mathewson's avatar
Nick Mathewson committed
526

527
528
529
    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, SOCK_DGRAM),
Cristian Toader's avatar
Cristian Toader committed
530
      SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
531
532
533
    if (rc)
      return rc;
  }
Cristian Toader's avatar
Cristian Toader committed
534

535
  rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
536
537
538
      SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_RAW),
      SCMP_CMP(2, SCMP_CMP_EQ, 0));
539
540
541
542
543
544
  if (rc)
    return rc;

  return 0;
}

545
546
547
548
/**
 * Function responsible for setting up the socketpair syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
Cristian Toader committed
549
550
551
552
static int
sb_socketpair(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
553
  (void) filter;
Cristian Toader's avatar
Cristian Toader committed
554
555

#ifdef __i386__
556
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair));
Cristian Toader's avatar
Cristian Toader committed
557
558
559
560
  if (rc)
    return rc;
#endif

561
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair),
Cristian Toader's avatar
Cristian Toader committed
562
563
564
565
566
567
568
569
      SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE),
      SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC));
  if (rc)
    return rc;

  return 0;
}

570
571
572
573
/**
 * Function responsible for setting up the setsockopt syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
574
static int
575
sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
576
577
{
  int rc = 0;
578
  (void) filter;
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
579

Cristian Toader's avatar
Cristian Toader committed
580
#ifdef __i386__
581
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt));
Cristian Toader's avatar
Cristian Toader committed
582
583
584
585
  if (rc)
    return rc;
#endif

586
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
587
588
589
590
591
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_REUSEADDR));
  if (rc)
    return rc;

592
593
594
595
596
597
598
599
600
601
602
603
  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;

604
#ifdef IP_TRANSPARENT
605
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt),
606
607
608
609
610
611
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
      SCMP_CMP(2, SCMP_CMP_EQ, IP_TRANSPARENT));
  if (rc)
    return rc;
#endif

Cristian Toader's avatar
fcntl64    
Cristian Toader committed
612
613
614
  return 0;
}

615
616
617
618
/**
 * Function responsible for setting up the getsockopt syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
Cristian Toader committed
619
620
static int
sb_getsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
Cristian Toader committed
621
622
{
  int rc = 0;
623
  (void) filter;
Cristian Toader's avatar
Cristian Toader committed
624
625

#ifdef __i386__
626
  rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt));
Cristian Toader's avatar
Cristian Toader committed
627
628
629
630
  if (rc)
    return rc;
#endif

631
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
Cristian Toader's avatar
Cristian Toader committed
632
633
634
635
636
637
638
639
      SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET),
      SCMP_CMP(2, SCMP_CMP_EQ, SO_ERROR));
  if (rc)
    return rc;

  return 0;
}

Cristian Toader's avatar
fcntl64    
Cristian Toader committed
640
#ifdef __NR_fcntl64
641
642
643
644
/**
 * Function responsible for setting up the fcntl64 syscall for
 * the seccomp filter sandbox.
 */
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
645
static int
646
sb_fcntl64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
647
648
{
  int rc = 0;
Nick Mathewson's avatar
Nick Mathewson committed
649
  (void) filter;
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
650

651
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
652
653
654
655
      SCMP_CMP(1, SCMP_CMP_EQ, F_GETFL));
  if (rc)
    return rc;

656
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
Cristian Toader's avatar
fcntl64    
Cristian Toader committed
657
658
659
660
661
      SCMP_CMP(1, SCMP_CMP_EQ, F_SETFL),
      SCMP_CMP(2, SCMP_CMP_EQ, O_RDWR|O_NONBLOCK));
  if (rc)
    return rc;

662
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
663
664
665
666
      SCMP_CMP(1, SCMP_CMP_EQ, F_GETFD));
  if (rc)
    return rc;

667
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64),
668
669
670
671
672
      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
673
674
675
676
  return 0;
}
#endif

677
678
679
680
681
682
/**
 * 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
683
static int
684
sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
Cristian Toader's avatar
Cristian Toader committed
685
686
{
  int rc = 0;
687
  (void) filter;
Cristian Toader's avatar
Cristian Toader committed
688

689
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
Cristian Toader's avatar
Cristian Toader committed
690
691
692
693
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_ADD));
  if (rc)
    return rc;

694
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
Cristian Toader's avatar
Cristian Toader committed
695
696
697
698
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_MOD));
  if (rc)
    return rc;

699
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl),
Cristian Toader's avatar
Cristian Toader committed
700
701
702
703
      SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_DEL));
  if (rc)
    return rc;

Cristian Toader's avatar
Cristian Toader committed
704
705
706
  return 0;
}

707
/**
708
709
710
711
712
 * Function responsible for setting up the fcntl64 syscall for
 * the seccomp filter sandbox.
 *
 * NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs
 * to be whitelisted in this function.
713
714
 */
static int
715
sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
716
717
{
  int rc = 0;
718
  (void) filter;
719

720
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
721
722
723
724
725
726
727
728
      SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_DUMPABLE));
  if (rc)
    return rc;

  return 0;
}

/**
729
730
731
732
733
 * Function responsible for setting up the fcntl64 syscall for
 * the seccomp filter sandbox.
 *
 * NOTE: does not NEED to be here.. currently only occurs before filter; will
 * keep just in case for the future.
734
735
 */
static int
736
sb_mprotect(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
737
738
{
  int rc = 0;
739
  (void) filter;
740

741
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
742
743
744
745
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ));
  if (rc)
    return rc;

746
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
747
748
749
750
      SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE));
  if (rc)
    return rc;

751
752
753
  return 0;
}

754
755
756
757
/**
 * Function responsible for setting up the rt_sigprocmask syscall for
 * the seccomp filter sandbox.
 */
758
static int
759
sb_rt_sigprocmask(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
760
761
{
  int rc = 0;
762
  (void) filter;
763

764
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
765
766
767
768
      SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK));
  if (rc)
    return rc;

769
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask),
770
771
772
773
      SCMP_CMP(0, SCMP_CMP_EQ, SIG_SETMASK));
  if (rc)
    return rc;

774
775
776
777
  return 0;
}

/**
778
779
780
781
 * Function responsible for setting up the flock syscall for
 * the seccomp filter sandbox.
 *
 *  NOTE: does not need to be here, occurs before filter is applied.
782
783
 */
static int
784
sb_flock(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
785
786
{
  int rc = 0;
787
  (void) filter;
788

789
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(flock),
790
791
792
793
      SCMP_CMP(1, SCMP_CMP_EQ, LOCK_EX|LOCK_NB));
  if (rc)
    return rc;

794
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(flock),
Cristian Toader's avatar
Cristian Toader committed
795
796
797
798
      SCMP_CMP(1, SCMP_CMP_EQ, LOCK_UN));
  if (rc)
    return rc;

799
800
801
  return 0;
}

802
803
804
805
/**
 * Function responsible for setting up the futex syscall for
 * the seccomp filter sandbox.
 */
806
static int
807
sb_futex(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
808
809
{
  int rc = 0;
810
  (void) filter;
811

812
  // can remove
813
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex),
814
815
816
817
818
      SCMP_CMP(1, SCMP_CMP_EQ,
          FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME));
  if (rc)
    return rc;

819
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex),
820
821
822
823
      SCMP_CMP(1, SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE));
  if (rc)
    return rc;

824
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex),
825
826
827
828
      SCMP_CMP(1, SCMP_CMP_EQ, FUTEX_WAIT_PRIVATE));
  if (rc)
    return rc;

829
830
831
832
  return 0;
}

/**
833
834
835
836
 * Function responsible for setting up the mremap syscall for
 * the seccomp filter sandbox.
 *
 *  NOTE: so far only occurs before filter is applied.
837
838
 */
static int
839
sb_mremap(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
840
841
{
  int rc = 0;
842
  (void) filter;
843

844
  rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mremap),
845
      SCMP_CMP(3, SCMP_CMP_EQ, MREMAP_MAYMOVE));
846
847
848
849
850
851
  if (rc)
    return rc;

  return 0;
}

852
853
854
855
/**
 * Function responsible for setting up the poll syscall for
 * the seccomp filter sandbox.
 */
856
static int
857
sb_poll(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
858
859
{
  int rc = 0;
860
  (void) filter;
861

862
  rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll),
863
864
865
866
867
868
869
870
      SCMP_CMP(1, SCMP_CMP_EQ, 1),
      SCMP_CMP(2, SCMP_CMP_EQ, 10));
  if (rc)
    return rc;

  return 0;
}

871
#ifdef __NR_stat64
872
873
874
875
/**
 * Function responsible for setting up the stat64 syscall for
 * the seccomp filter sandbox.
 */
876
877
878
879
880
881
882
883
static int
sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
{
  int rc = 0;
  sandbox_cfg_t *elem = NULL;

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

    if (param != NULL && param->prot == 1 && (param->syscall == SCMP_SYS(open)
        || param->syscall == SCMP_SYS(stat64))) {
888
      rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat64),
889
          SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
890
      if (rc != 0) {
Cristian Toader's avatar
Cristian Toader committed
891
892
        log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
            "libseccomp  error %d", rc);
893
894
895
896
897
898
899
900
901
        return rc;
      }
    }
  }

  return 0;
}
#endif

902
903
904
905
/**
 * Array of function pointers responsible for filtering different syscalls at
 * a parameter level.
 */
906
907
static sandbox_filter_func_t filter_func[] = {
    sb_rt_sigaction,
908
    sb_rt_sigprocmask,
909
#if 0
910
    sb_execve,
911
#endif
912
913
    sb_time,
    sb_accept4,
Nick Mathewson's avatar
Nick Mathewson committed
914
#ifdef __NR_mmap2
915
    sb_mmap2,
Nick Mathewson's avatar
Nick Mathewson committed
916
#endif
917
    sb_open,
918
    sb_openat,
919
    sb__sysctl,
920
    sb_rename,
Nick Mathewson's avatar
Nick Mathewson committed
921
#ifdef __NR_fcntl64
Cristian Toader's avatar
Cristian Toader committed
922
    sb_fcntl64,
Nick Mathewson's avatar
Nick Mathewson committed
923
#endif
924
925
926
927
928
    sb_epoll_ctl,
    sb_prctl,
    sb_mprotect,
    sb_flock,
    sb_futex,
929
    sb_mremap,
930
    sb_poll,
Nick Mathewson's avatar
Nick Mathewson committed
931
#ifdef __NR_stat64
932
    sb_stat64,
Nick Mathewson's avatar
Nick Mathewson committed
933
#endif
934
935

    sb_socket,
Cristian Toader's avatar
Cristian Toader committed
936
937
938
    sb_setsockopt,
    sb_getsockopt,
    sb_socketpair
939
940
};

941
const char *
942
sandbox_intern_string(const char *str)
943
944
945
{
  sandbox_cfg_t *elem;

946
  if (str == NULL)
947
948
    return NULL;

949
  for (elem = filter_dynamic; elem != NULL; elem = elem->next) {
950
951
    smp_param_t *param = elem->param;

952
953
954
955
956
957
958
    if (param->prot) {
      if (!strcmp(str, (char*)(param->value))) {
        return (char*)param->value;
      }
      if (param->value2 && !strcmp(str, (char*)param->value2)) {
        return (char*)param->value2;
      }
959
960
961
    }
  }

962
963
  if (sandbox_active)
    log_warn(LD_BUG, "No interned sandbox parameter found for %s", str);
964
  return str;
965
966
}

967
968
969
970
971
/** DOCDOC */
static int
prot_strings_helper(strmap_t *locations,
                    char **pr_mem_next_p,
                    size_t *pr_mem_left_p,
972
                    char **value_p)
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
{
  char *param_val;
  size_t param_size;
  void *location;

  if (*value_p == 0)
    return 0;

  param_val = (char*) *value_p;
  param_size = strlen(param_val) + 1;
  location = strmap_get(locations, param_val);

  if (location) {
    // We already interned this string.
    tor_free(param_val);
988
    *value_p = location;
989
990
991
992
993
994
995
996
    return 0;
  } else if (*pr_mem_left_p >= param_size) {
    // copy to protected
    location = *pr_mem_next_p;
    memcpy(location, param_val, param_size);

    // re-point el parameter to protected
    tor_free(param_val);
997
    *value_p = location;
998
999
1000

    strmap_set(locations, location, location); /* good real estate advice */