Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
* You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "SandboxFilter.h"
8
#include "SandboxFilterUtil.h"
9
10
#include "Sandbox.h" // for ContentProcessSandboxParams
11
#include "SandboxBrokerClient.h"
12
#include "SandboxInfo.h"
13
#include "SandboxInternal.h"
14
#include "SandboxLogging.h"
15
#include "SandboxOpenedFiles.h"
16
#include "mozilla/Move.h"
17
#include "mozilla/PodOperations.h"
18
#include "mozilla/TemplateLib.h"
19
#include "mozilla/UniquePtr.h"
20
#include "prenv.h"
21
22
#include <errno.h>
23
#include <fcntl.h>
24
#include <linux/ioctl.h>
25
#include <linux/ipc.h>
26
#include <linux/net.h>
27
#include <linux/sched.h>
28
#include <string.h>
29
#include <sys/ioctl.h>
30
#include <sys/mman.h>
31
#include <sys/prctl.h>
32
#include <sys/socket.h>
33
#include <sys/syscall.h>
34
#include <sys/un.h>
35
#include <sys/utsname.h>
36
#include <time.h>
37
#include <unistd.h>
38
#include <vector>
39
#include <algorithm>
40
41
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
42
#include "sandbox/linux/system_headers/linux_seccomp.h"
43
#include "sandbox/linux/system_headers/linux_syscalls.h"
44
45
using namespace sandbox::bpf_dsl;
46
#define CASES SANDBOX_BPF_DSL_CASES
47
48
// Fill in defines in case of old headers.
49
// (Warning: these are wrong on PA-RISC.)
50
#ifndef MADV_HUGEPAGE
51
# define MADV_HUGEPAGE 14
52
#endif
53
#ifndef MADV_NOHUGEPAGE
54
# define MADV_NOHUGEPAGE 15
55
#endif
56
#ifndef MADV_DONTDUMP
57
# define MADV_DONTDUMP 16
58
#endif
59
60
// Added in Linux 4.5; see bug 1303813.
61
#ifndef MADV_FREE
62
# define MADV_FREE 8
63
#endif
64
65
#ifndef PR_SET_PTRACER
66
# define PR_SET_PTRACER 0x59616d61
67
#endif
68
69
// The headers define O_LARGEFILE as 0 on x86_64, but we need the
70
// actual value because it shows up in file flags.
71
#define O_LARGEFILE_REAL 00100000
72
73
// To avoid visual confusion between "ifdef ANDROID" and "ifndef ANDROID":
74
#ifndef ANDROID
75
# define DESKTOP
76
#endif
77
78
// This file defines the seccomp-bpf system call filter policies.
79
// See also SandboxFilterUtil.h, for the CASES_FOR_* macros and
80
// SandboxFilterBase::Evaluate{Socket,Ipc}Call.
81
//
82
// One important difference from how Chromium bpf_dsl filters are
83
// normally interpreted: returning -ENOSYS from a Trap() handler
84
// indicates an unexpected system call; SigSysHandler() in Sandbox.cpp
85
// will detect this, request a crash dump, and terminate the process.
86
// This does not apply to using Error(ENOSYS) in the policy, so that
87
// can be used if returning an actual ENOSYS is needed.
88
89
namespace mozilla {
90
91
// This class allows everything used by the sandbox itself, by the
92
// core IPC code, by the crash reporter, or other core code. It also
93
// contains support for brokering file operations, but file access is
94
// denied if no broker client is provided by the concrete class.
95
class SandboxPolicyCommon : public SandboxPolicyBase {
96
protected:
97
enum class ShmemUsage {
98
MAY_CREATE,
99
ONLY_USE,
100
};
101
102
SandboxBrokerClient* mBroker;
103
ShmemUsage mShmemUsage;
104
105
explicit SandboxPolicyCommon(SandboxBrokerClient* aBroker,
106
ShmemUsage aShmemUsage = ShmemUsage::MAY_CREATE)
107
: mBroker(aBroker), mShmemUsage(aShmemUsage) {}
108
109
SandboxPolicyCommon() : SandboxPolicyCommon(nullptr, ShmemUsage::ONLY_USE) {}
110
111
typedef const sandbox::arch_seccomp_data& ArgsRef;
112
113
static intptr_t BlockedSyscallTrap(ArgsRef aArgs, void* aux) {
114
MOZ_ASSERT(!aux);
115
return -ENOSYS;
116
}
117
118
// Convert Unix-style "return -1 and set errno" APIs back into the
119
// Linux ABI "return -err" style.
120
static intptr_t ConvertError(long rv) { return rv < 0 ? -errno : rv; }
121
122
template <typename... Args>
123
static intptr_t DoSyscall(long nr, Args... args) {
124
static_assert(tl::And<(sizeof(Args) <= sizeof(void*))...>::value,
125
"each syscall arg is at most one word");
126
return ConvertError(syscall(nr, args...));
127
}
128
129
private:
130
// Bug 1093893: Translate tkill to tgkill for pthread_kill; fixed in
131
// bionic commit 10c8ce59a (in JB and up; API level 16 = Android 4.1).
132
// Bug 1376653: musl also needs this, and security-wise it's harmless.
133
static intptr_t TKillCompatTrap(ArgsRef aArgs, void* aux) {
134
auto tid = static_cast<pid_t>(aArgs.args[0]);
135
auto sig = static_cast<int>(aArgs.args[1]);
136
return DoSyscall(__NR_tgkill, getpid(), tid, sig);
137
}
138
139
static intptr_t SetNoNewPrivsTrap(ArgsRef& aArgs, void* aux) {
140
if (gSetSandboxFilter == nullptr) {
141
// Called after BroadcastSetThreadSandbox finished, therefore
142
// not our doing and not expected.
143
return BlockedSyscallTrap(aArgs, nullptr);
144
}
145
// Signal that the filter is already in place.
146
return -ETXTBSY;
147
}
148
149
// Trap handlers for filesystem brokering.
150
// (The amount of code duplication here could be improved....)
151
#ifdef __NR_open
152
static intptr_t OpenTrap(ArgsRef aArgs, void* aux) {
153
auto broker = static_cast<SandboxBrokerClient*>(aux);
154
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
155
auto flags = static_cast<int>(aArgs.args[1]);
156
return broker->Open(path, flags);
157
}
158
#endif
159
160
static intptr_t OpenAtTrap(ArgsRef aArgs, void* aux) {
161
auto broker = static_cast<SandboxBrokerClient*>(aux);
162
auto fd = static_cast<int>(aArgs.args[0]);
163
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
164
auto flags = static_cast<int>(aArgs.args[2]);
165
if (fd != AT_FDCWD && path[0] != '/') {
166
SANDBOX_LOG_ERROR("unsupported fd-relative openat(%d, \"%s\", 0%o)", fd,
167
path, flags);
168
return BlockedSyscallTrap(aArgs, nullptr);
169
}
170
return broker->Open(path, flags);
171
}
172
173
#ifdef __NR_access
174
static intptr_t AccessTrap(ArgsRef aArgs, void* aux) {
175
auto broker = static_cast<SandboxBrokerClient*>(aux);
176
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
177
auto mode = static_cast<int>(aArgs.args[1]);
178
return broker->Access(path, mode);
179
}
180
#endif
181
182
static intptr_t AccessAtTrap(ArgsRef aArgs, void* aux) {
183
auto broker = static_cast<SandboxBrokerClient*>(aux);
184
auto fd = static_cast<int>(aArgs.args[0]);
185
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
186
auto mode = static_cast<int>(aArgs.args[2]);
187
// Linux's faccessat syscall has no "flags" argument. Attempting
188
// to handle the flags != 0 case is left to userspace; this is
189
// impossible to do correctly in all cases, but that's not our
190
// problem.
191
if (fd != AT_FDCWD && path[0] != '/') {
192
SANDBOX_LOG_ERROR("unsupported fd-relative faccessat(%d, \"%s\", %d)", fd,
193
path, mode);
194
return BlockedSyscallTrap(aArgs, nullptr);
195
}
196
return broker->Access(path, mode);
197
}
198
199
static intptr_t StatTrap(ArgsRef aArgs, void* aux) {
200
auto broker = static_cast<SandboxBrokerClient*>(aux);
201
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
202
auto buf = reinterpret_cast<statstruct*>(aArgs.args[1]);
203
return broker->Stat(path, buf);
204
}
205
206
static intptr_t LStatTrap(ArgsRef aArgs, void* aux) {
207
auto broker = static_cast<SandboxBrokerClient*>(aux);
208
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
209
auto buf = reinterpret_cast<statstruct*>(aArgs.args[1]);
210
return broker->LStat(path, buf);
211
}
212
213
static intptr_t StatAtTrap(ArgsRef aArgs, void* aux) {
214
auto broker = static_cast<SandboxBrokerClient*>(aux);
215
auto fd = static_cast<int>(aArgs.args[0]);
216
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
217
auto buf = reinterpret_cast<statstruct*>(aArgs.args[2]);
218
auto flags = static_cast<int>(aArgs.args[3]);
219
if (fd != AT_FDCWD && path[0] != '/') {
220
SANDBOX_LOG_ERROR("unsupported fd-relative fstatat(%d, \"%s\", %p, %d)",
221
fd, path, buf, flags);
222
return BlockedSyscallTrap(aArgs, nullptr);
223
}
224
if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0) {
225
SANDBOX_LOG_ERROR("unsupported flags %d in fstatat(%d, \"%s\", %p, %d)",
226
(flags & ~AT_SYMLINK_NOFOLLOW), fd, path, buf, flags);
227
return BlockedSyscallTrap(aArgs, nullptr);
228
}
229
return (flags & AT_SYMLINK_NOFOLLOW) == 0 ? broker->Stat(path, buf)
230
: broker->LStat(path, buf);
231
}
232
233
static intptr_t ChmodTrap(ArgsRef aArgs, void* aux) {
234
auto broker = static_cast<SandboxBrokerClient*>(aux);
235
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
236
auto mode = static_cast<mode_t>(aArgs.args[1]);
237
return broker->Chmod(path, mode);
238
}
239
240
static intptr_t LinkTrap(ArgsRef aArgs, void* aux) {
241
auto broker = static_cast<SandboxBrokerClient*>(aux);
242
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
243
auto path2 = reinterpret_cast<const char*>(aArgs.args[1]);
244
return broker->Link(path, path2);
245
}
246
247
static intptr_t SymlinkTrap(ArgsRef aArgs, void* aux) {
248
auto broker = static_cast<SandboxBrokerClient*>(aux);
249
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
250
auto path2 = reinterpret_cast<const char*>(aArgs.args[1]);
251
return broker->Symlink(path, path2);
252
}
253
254
static intptr_t RenameTrap(ArgsRef aArgs, void* aux) {
255
auto broker = static_cast<SandboxBrokerClient*>(aux);
256
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
257
auto path2 = reinterpret_cast<const char*>(aArgs.args[1]);
258
return broker->Rename(path, path2);
259
}
260
261
static intptr_t MkdirTrap(ArgsRef aArgs, void* aux) {
262
auto broker = static_cast<SandboxBrokerClient*>(aux);
263
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
264
auto mode = static_cast<mode_t>(aArgs.args[1]);
265
return broker->Mkdir(path, mode);
266
}
267
268
static intptr_t RmdirTrap(ArgsRef aArgs, void* aux) {
269
auto broker = static_cast<SandboxBrokerClient*>(aux);
270
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
271
return broker->Rmdir(path);
272
}
273
274
static intptr_t UnlinkTrap(ArgsRef aArgs, void* aux) {
275
auto broker = static_cast<SandboxBrokerClient*>(aux);
276
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
277
return broker->Unlink(path);
278
}
279
280
static intptr_t ReadlinkTrap(ArgsRef aArgs, void* aux) {
281
auto broker = static_cast<SandboxBrokerClient*>(aux);
282
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
283
auto buf = reinterpret_cast<char*>(aArgs.args[1]);
284
auto size = static_cast<size_t>(aArgs.args[2]);
285
return broker->Readlink(path, buf, size);
286
}
287
288
static intptr_t ReadlinkAtTrap(ArgsRef aArgs, void* aux) {
289
auto broker = static_cast<SandboxBrokerClient*>(aux);
290
auto fd = static_cast<int>(aArgs.args[0]);
291
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
292
auto buf = reinterpret_cast<char*>(aArgs.args[2]);
293
auto size = static_cast<size_t>(aArgs.args[3]);
294
if (fd != AT_FDCWD && path[0] != '/') {
295
SANDBOX_LOG_ERROR("unsupported fd-relative readlinkat(%d, %s, %p, %u)",
296
fd, path, buf, size);
297
return BlockedSyscallTrap(aArgs, nullptr);
298
}
299
return broker->Readlink(path, buf, size);
300
}
301
302
static intptr_t SocketpairDatagramTrap(ArgsRef aArgs, void* aux) {
303
auto fds = reinterpret_cast<int*>(aArgs.args[3]);
304
// Return sequential packet sockets instead of the expected
305
// datagram sockets; see bug 1355274 for details.
306
return ConvertError(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
307
}
308
309
static intptr_t SocketpairUnpackTrap(ArgsRef aArgs, void* aux) {
310
#ifdef __NR_socketpair
311
auto argsPtr = reinterpret_cast<unsigned long*>(aArgs.args[1]);
312
return DoSyscall(__NR_socketpair, argsPtr[0], argsPtr[1], argsPtr[2],
313
argsPtr[3]);
314
#else
315
MOZ_CRASH("unreachable?");
316
return -ENOSYS;
317
#endif
318
}
319
320
public:
321
ResultExpr InvalidSyscall() const override {
322
return Trap(BlockedSyscallTrap, nullptr);
323
}
324
325
virtual ResultExpr ClonePolicy(ResultExpr failPolicy) const {
326
// Allow use for simple thread creation (pthread_create) only.
327
328
// WARNING: s390 and cris pass the flags in the second arg -- see
329
// CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
330
// don't support seccomp-bpf on those archs yet.
331
Arg<int> flags(0);
332
333
// The exact flags used can vary. CLONE_DETACHED is used by musl
334
// and by old versions of Android (<= JB 4.2), but it's been
335
// ignored by the kernel since the beginning of the Git history.
336
//
337
// If we ever need to support Android <= KK 4.4 again, SETTLS
338
// and the *TID flags will need to be made optional.
339
static const int flags_required =
340
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
341
CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID |
342
CLONE_CHILD_CLEARTID;
343
static const int flags_optional = CLONE_DETACHED;
344
345
return If((flags & ~flags_optional) == flags_required, Allow())
346
.Else(failPolicy);
347
}
348
349
virtual ResultExpr PrctlPolicy() const {
350
// Note: this will probably need PR_SET_VMA if/when it's used on
351
// Android without being overridden by an allow-all policy, and
352
// the constant will need to be defined locally.
353
Arg<int> op(0);
354
return Switch(op)
355
.CASES((PR_GET_SECCOMP, // BroadcastSetThreadSandbox, etc.
356
PR_SET_NAME, // Thread creation
357
PR_SET_DUMPABLE, // Crash reporting
358
PR_SET_PTRACER), // Debug-mode crash handling
359
Allow())
360
.Default(InvalidSyscall());
361
}
362
363
Maybe<ResultExpr> EvaluateSocketCall(int aCall,
364
bool aHasArgs) const override {
365
switch (aCall) {
366
case SYS_RECVMSG:
367
case SYS_SENDMSG:
368
return Some(Allow());
369
370
case SYS_SOCKETPAIR: {
371
// Allow "safe" (always connected) socketpairs when using the
372
// file broker.
373
if (mBroker == nullptr) {
374
return Nothing();
375
}
376
// See bug 1066750.
377
if (!aHasArgs) {
378
// If this is a socketcall(2) platform, but the kernel also
379
// supports separate syscalls (>= 4.2.0), we can unpack the
380
// arguments and filter them.
381
if (HasSeparateSocketCalls()) {
382
return Some(Trap(SocketpairUnpackTrap, nullptr));
383
}
384
// Otherwise, we can't filter the args if the platform passes
385
// them by pointer.
386
return Some(Allow());
387
}
388
Arg<int> domain(0), type(1);
389
return Some(
390
If(domain == AF_UNIX,
391
Switch(type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
392
.Case(SOCK_STREAM, Allow())
393
.Case(SOCK_SEQPACKET, Allow())
394
// This is used only by content (and only for
395
// direct PulseAudio, which is deprecated) but it
396
// doesn't increase attack surface:
397
.Case(SOCK_DGRAM, Trap(SocketpairDatagramTrap, nullptr))
398
.Default(InvalidSyscall()))
399
.Else(InvalidSyscall()));
400
}
401
402
default:
403
return Nothing();
404
}
405
}
406
407
ResultExpr EvaluateSyscall(int sysno) const override {
408
// If a file broker client was provided, route syscalls to it;
409
// otherwise, fall through to the main policy, which will deny
410
// them.
411
if (mBroker != nullptr) {
412
switch (sysno) {
413
case __NR_open:
414
return Trap(OpenTrap, mBroker);
415
case __NR_openat:
416
return Trap(OpenAtTrap, mBroker);
417
case __NR_access:
418
return Trap(AccessTrap, mBroker);
419
case __NR_faccessat:
420
return Trap(AccessAtTrap, mBroker);
421
CASES_FOR_stat:
422
return Trap(StatTrap, mBroker);
423
CASES_FOR_lstat:
424
return Trap(LStatTrap, mBroker);
425
CASES_FOR_fstatat:
426
return Trap(StatAtTrap, mBroker);
427
// Used by new libc and Rust's stdlib, if available.
428
// We don't have broker support yet so claim it does not exist.
429
case __NR_statx:
430
return Error(ENOSYS);
431
case __NR_chmod:
432
return Trap(ChmodTrap, mBroker);
433
case __NR_link:
434
return Trap(LinkTrap, mBroker);
435
case __NR_mkdir:
436
return Trap(MkdirTrap, mBroker);
437
case __NR_symlink:
438
return Trap(SymlinkTrap, mBroker);
439
case __NR_rename:
440
return Trap(RenameTrap, mBroker);
441
case __NR_rmdir:
442
return Trap(RmdirTrap, mBroker);
443
case __NR_unlink:
444
return Trap(UnlinkTrap, mBroker);
445
case __NR_readlink:
446
return Trap(ReadlinkTrap, mBroker);
447
case __NR_readlinkat:
448
return Trap(ReadlinkAtTrap, mBroker);
449
}
450
}
451
452
switch (sysno) {
453
// Timekeeping
454
case __NR_clock_gettime: {
455
Arg<clockid_t> clk_id(0);
456
return If(clk_id == CLOCK_MONOTONIC, Allow())
457
#ifdef CLOCK_MONOTONIC_COARSE
458
// Used by SandboxReporter, among other things.
459
.ElseIf(clk_id == CLOCK_MONOTONIC_COARSE, Allow())
460
#endif
461
.ElseIf(clk_id == CLOCK_PROCESS_CPUTIME_ID, Allow())
462
.ElseIf(clk_id == CLOCK_REALTIME, Allow())
463
#ifdef CLOCK_REALTIME_COARSE
464
.ElseIf(clk_id == CLOCK_REALTIME_COARSE, Allow())
465
#endif
466
.ElseIf(clk_id == CLOCK_THREAD_CPUTIME_ID, Allow())
467
.Else(InvalidSyscall());
468
}
469
case __NR_gettimeofday:
470
#ifdef __NR_time
471
case __NR_time:
472
#endif
473
case __NR_nanosleep:
474
return Allow();
475
476
// Thread synchronization
477
case __NR_futex:
478
// FIXME: This could be more restrictive....
479
return Allow();
480
481
// Asynchronous I/O
482
case __NR_epoll_create1:
483
case __NR_epoll_create:
484
case __NR_epoll_wait:
485
case __NR_epoll_pwait:
486
case __NR_epoll_ctl:
487
case __NR_ppoll:
488
case __NR_poll:
489
return Allow();
490
491
// Used when requesting a crash dump.
492
case __NR_pipe:
493
return Allow();
494
495
// Metadata of opened files
496
CASES_FOR_fstat:
497
return Allow();
498
499
// Simple I/O
500
case __NR_write:
501
case __NR_read:
502
case __NR_readv:
503
case __NR_writev: // see SandboxLogging.cpp
504
CASES_FOR_lseek:
505
return Allow();
506
507
CASES_FOR_ftruncate:
508
switch (mShmemUsage) {
509
case ShmemUsage::MAY_CREATE:
510
return Allow();
511
case ShmemUsage::ONLY_USE:
512
return InvalidSyscall();
513
default:
514
MOZ_CRASH("unreachable");
515
}
516
517
// Used by our fd/shm classes
518
case __NR_dup:
519
return Allow();
520
521
// Memory mapping
522
CASES_FOR_mmap:
523
case __NR_munmap:
524
return Allow();
525
526
// ipc::Shmem; also, glibc when creating threads:
527
case __NR_mprotect:
528
return Allow();
529
530
#if !defined(MOZ_MEMORY)
531
// No jemalloc means using a system allocator like glibc
532
// that might use brk.
533
case __NR_brk:
534
return Allow();
535
#endif
536
537
// madvise hints used by malloc; see bug 1303813 and bug 1364533
538
case __NR_madvise: {
539
Arg<int> advice(2);
540
return If(advice == MADV_DONTNEED, Allow())
541
.ElseIf(advice == MADV_FREE, Allow())
542
.ElseIf(advice == MADV_HUGEPAGE, Allow())
543
.ElseIf(advice == MADV_NOHUGEPAGE, Allow())
544
#ifdef MOZ_ASAN
545
.ElseIf(advice == MADV_DONTDUMP, Allow())
546
#endif
547
.Else(InvalidSyscall());
548
}
549
550
// musl libc will set this up in pthreads support.
551
case __NR_membarrier:
552
return Allow();
553
554
// Signal handling
555
#if defined(ANDROID) || defined(MOZ_ASAN)
556
case __NR_sigaltstack:
557
#endif
558
CASES_FOR_sigreturn:
559
CASES_FOR_sigprocmask:
560
CASES_FOR_sigaction:
561
return Allow();
562
563
// Send signals within the process (raise(), profiling, etc.)
564
case __NR_tgkill: {
565
Arg<pid_t> tgid(0);
566
return If(tgid == getpid(), Allow()).Else(InvalidSyscall());
567
}
568
569
// Polyfill with tgkill; see above.
570
case __NR_tkill:
571
return Trap(TKillCompatTrap, nullptr);
572
573
// Yield
574
case __NR_sched_yield:
575
return Allow();
576
577
// Thread creation.
578
case __NR_clone:
579
return ClonePolicy(InvalidSyscall());
580
581
// More thread creation.
582
#ifdef __NR_set_robust_list
583
case __NR_set_robust_list:
584
return Allow();
585
#endif
586
#ifdef ANDROID
587
case __NR_set_tid_address:
588
return Allow();
589
#endif
590
591
// prctl
592
case __NR_prctl: {
593
if (SandboxInfo::Get().Test(SandboxInfo::kHasSeccompTSync)) {
594
return PrctlPolicy();
595
}
596
597
Arg<int> option(0);
598
return If(option == PR_SET_NO_NEW_PRIVS,
599
Trap(SetNoNewPrivsTrap, nullptr))
600
.Else(PrctlPolicy());
601
}
602
603
// NSPR can call this when creating a thread, but it will accept a
604
// polite "no".
605
case __NR_getpriority:
606
// But if thread creation races with sandbox startup, that call
607
// could succeed, and then we get one of these:
608
case __NR_setpriority:
609
return Error(EACCES);
610
611
// Stack bounds are obtained via pthread_getattr_np, which calls
612
// this but doesn't actually need it:
613
case __NR_sched_getaffinity:
614
return Error(ENOSYS);
615
616
// Read own pid/tid.
617
case __NR_getpid:
618
case __NR_gettid:
619
return Allow();
620
621
// Discard capabilities
622
case __NR_close:
623
return Allow();
624
625
// Machine-dependent stuff
626
#ifdef __arm__
627
case __ARM_NR_breakpoint:
628
case __ARM_NR_cacheflush:
629
case __ARM_NR_usr26: // FIXME: do we actually need this?
630
case __ARM_NR_usr32:
631
case __ARM_NR_set_tls:
632
return Allow();
633
#endif
634
635
// Needed when being debugged:
636
case __NR_restart_syscall:
637
return Allow();
638
639
// Terminate threads or the process
640
case __NR_exit:
641
case __NR_exit_group:
642
return Allow();
643
644
case __NR_getrandom:
645
return Allow();
646
647
#ifdef DESKTOP
648
// Bug 1543858: glibc's qsort calls sysinfo to check the
649
// memory size; it falls back to assuming there's enough RAM.
650
case __NR_sysinfo:
651
return Error(EPERM);
652
#endif
653
654
#ifdef MOZ_ASAN
655
// ASAN's error reporter wants to know if stderr is a tty.
656
case __NR_ioctl: {
657
Arg<int> fd(0);
658
return If(fd == STDERR_FILENO, Error(ENOTTY)).Else(InvalidSyscall());
659
}
660
661
// ...and before compiler-rt r209773, it will call readlink on
662
// /proc/self/exe and use the cached value only if that fails:
663
case __NR_readlink:
664
case __NR_readlinkat:
665
return Error(ENOENT);
666
667
// ...and if it found an external symbolizer, it will try to run it:
668
// (See also bug 1081242 comment #7.)
669
CASES_FOR_stat:
670
return Error(ENOENT);
671
#endif
672
673
default:
674
return SandboxPolicyBase::EvaluateSyscall(sysno);
675
}
676
}
677
};
678
679
// The process-type-specific syscall rules start here:
680
681
// The seccomp-bpf filter for content processes is not a true sandbox
682
// on its own; its purpose is attack surface reduction and syscall
683
// interception in support of a semantic sandboxing layer. On B2G
684
// this is the Android process permission model; on desktop,
685
// namespaces and chroot() will be used.
686
class ContentSandboxPolicy : public SandboxPolicyCommon {
687
private:
688
ContentProcessSandboxParams mParams;
689
bool mAllowSysV;
690
bool mUsingRenderDoc;
691
692
bool BelowLevel(int aLevel) const { return mParams.mLevel < aLevel; }
693
ResultExpr AllowBelowLevel(int aLevel, ResultExpr aOrElse) const {
694
return BelowLevel(aLevel) ? Allow() : std::move(aOrElse);
695
}
696
ResultExpr AllowBelowLevel(int aLevel) const {
697
return AllowBelowLevel(aLevel, InvalidSyscall());
698
}
699
700
static intptr_t GetPPidTrap(ArgsRef aArgs, void* aux) {
701
// In a pid namespace, getppid() will return 0. We will return 0 instead
702
// of the real parent pid to see what breaks when we introduce the
703
// pid namespace (Bug 1151624).
704
return 0;
705
}
706
707
static intptr_t StatFsTrap(ArgsRef aArgs, void* aux) {
708
// Warning: the kernel interface is not the C interface. The
709
// structs are different (<asm/statfs.h> vs. <sys/statfs.h>), and
710
// the statfs64 version takes an additional size parameter.
711
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
712
int fd = open(path, O_RDONLY | O_LARGEFILE);
713
if (fd < 0) {
714
return -errno;
715
}
716
717
intptr_t rv;
718
switch (aArgs.nr) {
719
case __NR_statfs: {
720
auto buf = reinterpret_cast<void*>(aArgs.args[1]);
721
rv = DoSyscall(__NR_fstatfs, fd, buf);
722
break;
723
}
724
#ifdef __NR_statfs64
725
case __NR_statfs64: {
726
auto sz = static_cast<size_t>(aArgs.args[1]);
727
auto buf = reinterpret_cast<void*>(aArgs.args[2]);
728
rv = DoSyscall(__NR_fstatfs64, fd, sz, buf);
729
break;
730
}
731
#endif
732
default:
733
MOZ_ASSERT(false);
734
rv = -ENOSYS;
735
}
736
737
close(fd);
738
return rv;
739
}
740
741
// This just needs to return something to stand in for the
742
// unconnected socket until ConnectTrap, below, and keep track of
743
// the socket type somehow. Half a socketpair *is* a socket, so it
744
// should result in minimal confusion in the caller.
745
static intptr_t FakeSocketTrapCommon(int domain, int type, int protocol) {
746
int fds[2];
747
// X11 client libs will still try to getaddrinfo() even for a
748
// local connection. Also, WebRTC still has vestigial network
749
// code trying to do things in the content process. Politely tell
750
// them no.
751
if (domain != AF_UNIX) {
752
return -EAFNOSUPPORT;
753
}
754
if (socketpair(domain, type, protocol, fds) != 0) {
755
return -errno;
756
}
757
close(fds[1]);
758
return fds[0];
759
}
760
761
static intptr_t FakeSocketTrap(ArgsRef aArgs, void* aux) {
762
return FakeSocketTrapCommon(static_cast<int>(aArgs.args[0]),
763
static_cast<int>(aArgs.args[1]),
764
static_cast<int>(aArgs.args[2]));
765
}
766
767
static intptr_t FakeSocketTrapLegacy(ArgsRef aArgs, void* aux) {
768
const auto innerArgs = reinterpret_cast<unsigned long*>(aArgs.args[1]);
769
770
return FakeSocketTrapCommon(static_cast<int>(innerArgs[0]),
771
static_cast<int>(innerArgs[1]),
772
static_cast<int>(innerArgs[2]));
773
}
774
775
static Maybe<int> DoGetSockOpt(int fd, int optname) {
776
int optval;
777
socklen_t optlen = sizeof(optval);
778
779
if (getsockopt(fd, SOL_SOCKET, optname, &optval, &optlen) != 0) {
780
return Nothing();
781
}
782
MOZ_RELEASE_ASSERT(static_cast<size_t>(optlen) == sizeof(optval));
783
return Some(optval);
784
}
785
786
// Substitute the newly connected socket from the broker for the
787
// original socket. This is meant to be used on a fd from
788
// FakeSocketTrap, above, but it should also work to simulate
789
// re-connect()ing a real connected socket.
790
//
791
// Warning: This isn't quite right if the socket is dup()ed, because
792
// other duplicates will still be the original socket, but hopefully
793
// nothing we're dealing with does that.
794
static intptr_t ConnectTrapCommon(SandboxBrokerClient* aBroker, int aFd,
795
const struct sockaddr_un* aAddr,
796
socklen_t aLen) {
797
if (aFd < 0) {
798
return -EBADF;
799
}
800
const auto maybeDomain = DoGetSockOpt(aFd, SO_DOMAIN);
801
if (!maybeDomain) {
802
return -errno;
803
}
804
if (*maybeDomain != AF_UNIX) {
805
return -EAFNOSUPPORT;
806
}
807
const auto maybeType = DoGetSockOpt(aFd, SO_TYPE);
808
if (!maybeType) {
809
return -errno;
810
}
811
const int oldFlags = fcntl(aFd, F_GETFL);
812
if (oldFlags == -1) {
813
return -errno;
814
}
815
const int newFd = aBroker->Connect(aAddr, aLen, *maybeType);
816
if (newFd < 0) {
817
return newFd;
818
}
819
// Copy over the nonblocking flag. The connect() won't be
820
// nonblocking in that case, but that shouldn't matter for
821
// AF_UNIX. The other fcntl-settable flags are either irrelevant
822
// for sockets (e.g., O_APPEND) or would be blocked by this
823
// seccomp-bpf policy, so they're ignored.
824
if (fcntl(newFd, F_SETFL, oldFlags & O_NONBLOCK) != 0) {
825
close(newFd);
826
return -errno;
827
}
828
if (dup2(newFd, aFd) < 0) {
829
close(newFd);
830
return -errno;
831
}
832
close(newFd);
833
return 0;
834
}
835
836
static intptr_t ConnectTrap(ArgsRef aArgs, void* aux) {
837
typedef const struct sockaddr_un* AddrPtr;
838
839
return ConnectTrapCommon(static_cast<SandboxBrokerClient*>(aux),
840
static_cast<int>(aArgs.args[0]),
841
reinterpret_cast<AddrPtr>(aArgs.args[1]),
842
static_cast<socklen_t>(aArgs.args[2]));
843
}
844
845
static intptr_t ConnectTrapLegacy(ArgsRef aArgs, void* aux) {
846
const auto innerArgs = reinterpret_cast<unsigned long*>(aArgs.args[1]);
847
typedef const struct sockaddr_un* AddrPtr;
848
849
return ConnectTrapCommon(static_cast<SandboxBrokerClient*>(aux),
850
static_cast<int>(innerArgs[0]),
851
reinterpret_cast<AddrPtr>(innerArgs[1]),
852
static_cast<socklen_t>(innerArgs[2]));
853
}
854
855
public:
856
ContentSandboxPolicy(SandboxBrokerClient* aBroker,
857
ContentProcessSandboxParams&& aParams)
858
: SandboxPolicyCommon(aBroker),
859
mParams(std::move(aParams)),
860
mAllowSysV(PR_GetEnv("MOZ_SANDBOX_ALLOW_SYSV") != nullptr),
861
mUsingRenderDoc(PR_GetEnv("RENDERDOC_CAPTUREOPTS") != nullptr) {}
862
863
~ContentSandboxPolicy() override = default;
864
865
Maybe<ResultExpr> EvaluateSocketCall(int aCall,
866
bool aHasArgs) const override {
867
switch (aCall) {
868
case SYS_RECVFROM:
869
case SYS_SENDTO:
870
case SYS_SENDMMSG: // libresolv via libasyncns; see bug 1355274
871
return Some(Allow());
872
873
#ifdef ANDROID
874
case SYS_SOCKET:
875
return Some(Error(EACCES));
876
#else // #ifdef DESKTOP
877
case SYS_SOCKET: {
878
const auto trapFn = aHasArgs ? FakeSocketTrap : FakeSocketTrapLegacy;
879
return Some(AllowBelowLevel(4, Trap(trapFn, nullptr)));
880
}
881
case SYS_CONNECT: {
882
const auto trapFn = aHasArgs ? ConnectTrap : ConnectTrapLegacy;
883
return Some(AllowBelowLevel(4, Trap(trapFn, mBroker)));
884
}
885
case SYS_ACCEPT:
886
case SYS_ACCEPT4:
887
if (mUsingRenderDoc) {
888
return Some(Allow());
889
}
890
return SandboxPolicyCommon::EvaluateSocketCall(aCall, aHasArgs);
891
case SYS_RECV:
892
case SYS_SEND:
893
case SYS_GETSOCKOPT:
894
case SYS_SETSOCKOPT:
895
case SYS_GETSOCKNAME:
896
case SYS_GETPEERNAME:
897
case SYS_SHUTDOWN:
898
return Some(Allow());
899
#endif
900
default:
901
return SandboxPolicyCommon::EvaluateSocketCall(aCall, aHasArgs);
902
}
903
}
904
905
#ifdef DESKTOP
906
Maybe<ResultExpr> EvaluateIpcCall(int aCall) const override {
907
switch (aCall) {
908
// These are a problem: SysV IPC follows the Unix "same uid
909
// policy" and can't be restricted/brokered like file access.
910
// We're not using it directly, but there are some library
911
// dependencies that do; see ContentNeedsSysVIPC() in
912
// SandboxLaunch.cpp. Also, Cairo as used by GTK will sometimes
913
// try to use MIT-SHM, so shmget() is a non-fatal error. See
914
// also bug 1376910 and bug 1438401.
915
case SHMGET:
916
return Some(mAllowSysV ? Allow() : Error(EPERM));
917
case SHMCTL:
918
case SHMAT:
919
case SHMDT:
920
case SEMGET:
921
case SEMCTL:
922
case SEMOP:
923
if (mAllowSysV) {
924
return Some(Allow());
925
}
926
return SandboxPolicyCommon::EvaluateIpcCall(aCall);
927
default:
928
return SandboxPolicyCommon::EvaluateIpcCall(aCall);
929
}
930
}
931
#endif
932
933
#ifdef MOZ_PULSEAUDIO
934
ResultExpr PrctlPolicy() const override {
935
if (BelowLevel(4)) {
936
Arg<int> op(0);
937
return If(op == PR_GET_NAME, Allow())
938
.Else(SandboxPolicyCommon::PrctlPolicy());
939
}
940
return SandboxPolicyCommon::PrctlPolicy();
941
}
942
#endif
943
944
ResultExpr EvaluateSyscall(int sysno) const override {
945
// Straight allow for anything that got overriden via prefs
946
const auto& whitelist = mParams.mSyscallWhitelist;
947
if (std::find(whitelist.begin(), whitelist.end(), sysno) !=
948
whitelist.end()) {
949
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
950
SANDBOX_LOG_ERROR("Allowing syscall nr %d via whitelist", sysno);
951
}
952
return Allow();
953
}
954
955
// Level 1 allows direct filesystem access; higher levels use
956
// brokering (by falling through to the main policy and delegating
957
// to SandboxPolicyCommon).
958
if (BelowLevel(2)) {
959
MOZ_ASSERT(mBroker == nullptr);
960
switch (sysno) {
961
case __NR_open:
962
case __NR_openat:
963
case __NR_access:
964
case __NR_faccessat:
965
CASES_FOR_stat:
966
CASES_FOR_lstat:
967
CASES_FOR_fstatat:
968
case __NR_chmod:
969
case __NR_link:
970
case __NR_mkdir:
971
case __NR_symlink:
972
case __NR_rename:
973
case __NR_rmdir:
974
case __NR_unlink:
975
case __NR_readlink:
976
case __NR_readlinkat:
977
return Allow();
978
}
979
}
980
981
switch (sysno) {
982
#ifdef DESKTOP
983
case __NR_getppid:
984
return Trap(GetPPidTrap, nullptr);
985
986
CASES_FOR_statfs:
987
return Trap(StatFsTrap, nullptr);
988
989
// GTK's theme parsing tries to getcwd() while sandboxed, but
990
// only during Talos runs.
991
case __NR_getcwd:
992
return Error(ENOENT);
993
994
# ifdef MOZ_PULSEAUDIO
995
CASES_FOR_fchown:
996
case __NR_fchmod:
997
return AllowBelowLevel(4);
998
# endif
999
CASES_FOR_fstatfs: // fontconfig, pulseaudio, GIO (see also statfs)
1000
case __NR_flock: // graphics
1001
return Allow();
1002
1003
// Bug 1354731: proprietary GL drivers try to mknod() their devices
1004
# ifdef __NR_mknod
1005
case __NR_mknod:
1006
# endif
1007
case __NR_mknodat: {
1008
Arg<mode_t> mode(sysno == __NR_mknodat ? 2 : 1);
1009
return If((mode & S_IFMT) == S_IFCHR, Error(EPERM))
1010
.Else(InvalidSyscall());
1011
}
1012
// Bug 1438389: ...and nvidia GL will sometimes try to chown the devices
1013
# ifdef __NR_chown
1014
case __NR_chown:
1015
# endif
1016
case __NR_fchownat:
1017
return Error(EPERM);
1018
1019
// For ORBit called by GConf (on some systems) to get proxy
1020
// settings. Can remove when bug 1325242 happens in some form.
1021
case __NR_utime:
1022
return Error(EPERM);
1023
#endif
1024
1025
CASES_FOR_select:
1026
case __NR_pselect6:
1027
return Allow();
1028
1029
CASES_FOR_getdents:
1030
case __NR_writev:
1031
case __NR_pread64:
1032
#ifdef DESKTOP
1033
case __NR_pwrite64:
1034
case __NR_readahead:
1035
#endif
1036
return Allow();
1037
1038
case __NR_ioctl: {
1039
#ifdef MOZ_ALSA
1040
if (BelowLevel(4)) {
1041
return Allow();
1042
}
1043
#endif
1044
static const unsigned long kTypeMask = _IOC_TYPEMASK << _IOC_TYPESHIFT;
1045
static const unsigned long kTtyIoctls = TIOCSTI & kTypeMask;
1046
// On some older architectures (but not x86 or ARM), ioctls are
1047
// assigned type fields differently, and the TIOC/TC/FIO group
1048
// isn't all the same type. If/when we support those archs,
1049
// this would need to be revised (but really this should be a
1050
// default-deny policy; see below).
1051
static_assert(kTtyIoctls == (TCSETA & kTypeMask) &&
1052
kTtyIoctls == (FIOASYNC & kTypeMask),
1053
"tty-related ioctls use the same type");
1054
1055
Arg<unsigned long> request(1);
1056
auto shifted_type = request & kTypeMask;
1057
1058
// Rust's stdlib seems to use FIOCLEX instead of equivalent fcntls.
1059
return If(request == FIOCLEX, Allow())
1060
// Rust's stdlib also uses FIONBIO instead of equivalent fcntls.
1061
.ElseIf(request == FIONBIO, Allow())
1062
// ffmpeg, and anything else that calls isatty(), will be told
1063
// that nothing is a typewriter:
1064
.ElseIf(request == TCGETS, Error(ENOTTY))
1065
// Allow anything that isn't a tty ioctl, for now; bug 1302711
1066
// will cover changing this to a default-deny policy.
1067
.ElseIf(shifted_type != kTtyIoctls, Allow())
1068
.Else(SandboxPolicyCommon::EvaluateSyscall(sysno));
1069
}
1070
1071
CASES_FOR_fcntl : {
1072
Arg<int> cmd(1);
1073
Arg<int> flags(2);
1074
// Typical use of F_SETFL is to modify the flags returned by
1075
// F_GETFL and write them back, including some flags that
1076
// F_SETFL ignores. This is a default-deny policy in case any
1077
// new SETFL-able flags are added. (In particular we want to
1078
// forbid O_ASYNC; see bug 1328896, but also see bug 1408438.)
1079
static const int ignored_flags =
1080
O_ACCMODE | O_LARGEFILE_REAL | O_CLOEXEC;
1081
static const int allowed_flags = ignored_flags | O_APPEND | O_NONBLOCK;
1082
return Switch(cmd)
1083
// Close-on-exec is meaningless when execve isn't allowed, but
1084
// NSPR reads the bit and asserts that it has the expected value.
1085
.Case(F_GETFD, Allow())
1086
.Case(
1087
F_SETFD,
1088
If((flags & ~FD_CLOEXEC) == 0, Allow()).Else(InvalidSyscall()))
1089
.Case(F_GETFL, Allow())
1090
.Case(F_SETFL, If((flags & ~allowed_flags) == 0, Allow())
1091
.Else(InvalidSyscall()))
1092
.Case(F_DUPFD_CLOEXEC, Allow())
1093
// Nvidia GL and fontconfig (newer versions) use fcntl file locking.
1094
.Case(F_SETLK, Allow())
1095
#ifdef F_SETLK64
1096
.Case(F_SETLK64, Allow())
1097
#endif
1098
// Pulseaudio uses F_SETLKW, as does fontconfig.
1099
.Case(F_SETLKW, Allow())
1100
#ifdef F_SETLKW64
1101
.Case(F_SETLKW64, Allow())
1102
#endif
1103
.Default(SandboxPolicyCommon::EvaluateSyscall(sysno));
1104
}
1105
1106
case __NR_brk:
1107
// FIXME(bug 1510861) are we using any hints that aren't allowed
1108
// in SandboxPolicyCommon now?
1109
case __NR_madvise:
1110
// libc's realloc uses mremap (Bug 1286119); wasm does too (bug
1111
// 1342385).
1112
case __NR_mremap:
1113
return Allow();
1114
1115
// Bug 1462640: Mesa libEGL uses mincore to test whether values
1116
// are pointers, for reasons.
1117
case __NR_mincore: {
1118
Arg<size_t> length(1);
1119
return If(length == getpagesize(), Allow())
1120
.Else(SandboxPolicyCommon::EvaluateSyscall(sysno));
1121
}
1122
1123
case __NR_sigaltstack:
1124
return Allow();
1125
1126
#ifdef __NR_set_thread_area
1127
case __NR_set_thread_area:
1128
return Allow();
1129
#endif
1130
1131
case __NR_getrusage:
1132
case __NR_times:
1133
return Allow();
1134
1135
case __NR_dup2: // See ConnectTrapCommon
1136
return Allow();
1137
1138
CASES_FOR_getuid:
1139
CASES_FOR_getgid:
1140
CASES_FOR_geteuid:
1141
CASES_FOR_getegid:
1142
return Allow();
1143
1144
case __NR_fsync:
1145
case __NR_msync:
1146
return Allow();
1147
1148
case __NR_getpriority:
1149
case __NR_setpriority:
1150
case __NR_sched_get_priority_min:
1151
case __NR_sched_get_priority_max:
1152
case __NR_sched_getscheduler:
1153
case __NR_sched_setscheduler:
1154
case __NR_sched_getparam:
1155
case __NR_sched_setparam:
1156
#ifdef DESKTOP
1157
case __NR_sched_getaffinity:
1158
#endif
1159
return Allow();
1160
1161
#ifdef DESKTOP
1162
case __NR_sched_setaffinity:
1163
return Error(EPERM);
1164
#endif
1165
1166
#ifdef DESKTOP
1167
case __NR_pipe2:
1168
return Allow();
1169
1170
CASES_FOR_getrlimit:
1171
case __NR_clock_getres:
1172
CASES_FOR_getresuid:
1173
CASES_FOR_getresgid:
1174
return Allow();
1175
1176
case __NR_prlimit64: {
1177
// Allow only the getrlimit() use case. (glibc seems to use
1178
// only pid 0 to indicate the current process; pid == getpid()
1179
// is equivalent and could also be allowed if needed.)
1180
Arg<pid_t> pid(0);
1181
// This is really a const struct ::rlimit*, but Arg<> doesn't
1182
// work with pointers, only integer types.
1183
Arg<uintptr_t> new_limit(2);
1184
return If(AllOf(pid == 0, new_limit == 0), Allow())
1185
.Else(InvalidSyscall());
1186
}
1187
1188
// PulseAudio calls umask, even though it's unsafe in
1189
// multithreaded applications. But, allowing it here doesn't
1190
// really do anything one way or the other, now that file
1191
// accesses are brokered to another process.
1192
case __NR_umask:
1193
return AllowBelowLevel(4);
1194
1195
case __NR_kill: {
1196
if (BelowLevel(4)) {
1197
Arg<int> sig(1);
1198
// PulseAudio uses kill(pid, 0) to check if purported owners of
1199
// shared memory files are still alive; see bug 1397753 for more
1200
// details.
1201
return If(sig == 0, Error(EPERM)).Else(InvalidSyscall());
1202
}
1203
return InvalidSyscall();
1204
}
1205
1206
case __NR_wait4:
1207
# ifdef __NR_waitpid
1208
case __NR_waitpid:
1209
# endif
1210
// NSPR will start a thread to wait for child processes even if
1211
// fork() fails; see bug 227246 and bug 1299581.
1212
return Error(ECHILD);
1213
1214
case __NR_eventfd2:
1215
return Allow();
1216
1217
# ifdef __NR_memfd_create
1218
case __NR_memfd_create:
1219
return Allow();
1220
# endif
1221
1222
# ifdef __NR_rt_tgsigqueueinfo
1223
// Only allow to send signals within the process.
1224
case __NR_rt_tgsigqueueinfo: {
1225
Arg<pid_t> tgid(0);
1226
return If(tgid == getpid(), Allow()).Else(InvalidSyscall());
1227
}
1228
# endif
1229
1230
case __NR_mlock:
1231
case __NR_munlock:
1232
return Allow();
1233
1234
// We can't usefully allow fork+exec, even on a temporary basis;
1235
// the child would inherit the seccomp-bpf policy and almost
1236
// certainly die from an unexpected SIGSYS. We also can't have
1237
// fork() crash, currently, because there are too many system
1238
// libraries/plugins that try to run commands. But they can
1239
// usually do something reasonable on error.
1240
case __NR_clone:
1241
return ClonePolicy(Error(EPERM));
1242
1243
# ifdef __NR_fadvise64
1244
case __NR_fadvise64:
1245
return Allow();
1246
# endif
1247
1248
# ifdef __NR_fadvise64_64
1249
case __NR_fadvise64_64:
1250
return Allow();
1251
# endif
1252
1253
case __NR_fallocate:
1254
return Allow();
1255
1256
case __NR_get_mempolicy:
1257
return Allow();
1258
1259
#endif // DESKTOP
1260
1261
// nsSystemInfo uses uname (and we cache an instance, so
1262
// the info remains present even if we block the syscall)
1263
case __NR_uname:
1264
#ifdef DESKTOP
1265
case __NR_sysinfo:
1266
#endif
1267
return Allow();
1268
1269
#ifdef MOZ_JPROF
1270
case __NR_setitimer:
1271
return Allow();
1272
#endif // MOZ_JPROF
1273
1274
default:
1275
return SandboxPolicyCommon::EvaluateSyscall(sysno);
1276
}
1277
}
1278
};
1279
1280
UniquePtr<sandbox::bpf_dsl::Policy> GetContentSandboxPolicy(
1281
SandboxBrokerClient* aMaybeBroker, ContentProcessSandboxParams&& aParams) {
1282
return MakeUnique<ContentSandboxPolicy>(aMaybeBroker, std::move(aParams));
1283
}
1284
1285
// Unlike for content, the GeckoMediaPlugin seccomp-bpf policy needs
1286
// to be an effective sandbox by itself, because we allow GMP on Linux
1287
// systems where that's the only sandboxing mechanism we can use.
1288
//
1289
// Be especially careful about what this policy allows.
1290
class GMPSandboxPolicy : public SandboxPolicyCommon {
1291
static intptr_t OpenTrap(const sandbox::arch_seccomp_data& aArgs, void* aux) {
1292
const auto files = static_cast<const SandboxOpenedFiles*>(aux);
1293
const char* path;
1294
int flags;
1295
1296
switch (aArgs.nr) {
1297
#ifdef __NR_open
1298
case __NR_open:
1299
path = reinterpret_cast<const char*>(aArgs.args[0]);
1300
flags = static_cast<int>(aArgs.args[1]);
1301
break;
1302
#endif
1303
case __NR_openat:
1304
// The path has to be absolute to match the pre-opened file (see
1305
// assertion in ctor) so the dirfd argument is ignored.
1306
path = reinterpret_cast<const char*>(aArgs.args[1]);
1307
flags = static_cast<int>(aArgs.args[2]);
1308
break;
1309
default:
1310
MOZ_CRASH("unexpected syscall number");
1311
}
1312
1313
if ((flags & O_ACCMODE) != O_RDONLY) {
1314
SANDBOX_LOG_ERROR("non-read-only open of file %s attempted (flags=0%o)",
1315
path, flags);
1316
return -EROFS;
1317
}
1318
int fd = files->GetDesc(path);
1319
if (fd < 0) {
1320
// SandboxOpenedFile::GetDesc already logged about this, if appropriate.
1321
return -ENOENT;
1322
}
1323
return fd;
1324
}
1325
1326
static intptr_t SchedTrap(ArgsRef aArgs, void* aux) {
1327
const pid_t tid = syscall(__NR_gettid);
1328
if (aArgs.args[0] == static_cast<uint64_t>(tid)) {
1329
return DoSyscall(aArgs.nr, 0, static_cast<uintptr_t>(aArgs.args[1]),
1330
static_cast<uintptr_t>(aArgs.args[2]),
1331
static_cast<uintptr_t>(aArgs.args[3]),
1332
static_cast<uintptr_t>(aArgs.args[4]),
1333
static_cast<uintptr_t>(aArgs.args[5]));
1334
}
1335
SANDBOX_LOG_ERROR("unsupported tid in SchedTrap");
1336
return BlockedSyscallTrap(aArgs, nullptr);
1337
}
1338
1339
static intptr_t UnameTrap(const sandbox::arch_seccomp_data& aArgs,
1340
void* aux) {
1341
const auto buf = reinterpret_cast<struct utsname*>(aArgs.args[0]);
1342
PodZero(buf);
1343
// The real uname() increases fingerprinting risk for no benefit.
1344
// This is close enough.
1345
strcpy(buf->sysname, "Linux");
1346
strcpy(buf->version, "3");
1347
return 0;
1348
};
1349
1350
static intptr_t FcntlTrap(const sandbox::arch_seccomp_data& aArgs,
1351
void* aux) {
1352
const auto cmd = static_cast<int>(aArgs.args[1]);
1353
switch (cmd) {
1354
// This process can't exec, so the actual close-on-exec flag
1355
// doesn't matter; have it always read as true and ignore writes.
1356
case F_GETFD:
1357
return O_CLOEXEC;
1358
case F_SETFD:
1359
return 0;
1360
default:
1361
return -ENOSYS;
1362
}
1363
}
1364
1365
const SandboxOpenedFiles* mFiles;
1366
1367
public:
1368
explicit GMPSandboxPolicy(const SandboxOpenedFiles* aFiles)
1369
: mFiles(aFiles) {}
1370
1371
~GMPSandboxPolicy() override = default;
1372
1373
ResultExpr EvaluateSyscall(int sysno) const override {
1374
switch (sysno) {
1375
// Simulate opening the plugin file.
1376
#ifdef __NR_open
1377
case __NR_open:
1378
#endif
1379
case __NR_openat:
1380
return Trap(OpenTrap, mFiles);
1381
1382
case __NR_brk:
1383
// Because Firefox on glibc resorts to the fallback implementation
1384
// mentioned in bug 1576006, we must explicitly allow the get*id()
1385
// functions in order to use NSS in the clearkey CDM.
1386
CASES_FOR_getuid:
1387
CASES_FOR_getgid:
1388
CASES_FOR_geteuid:
1389
CASES_FOR_getegid:
1390
return Allow();
1391
case __NR_sched_get_priority_min:
1392
case __NR_sched_get_priority_max:
1393
return Allow();
1394
case __NR_sched_getparam:
1395
case __NR_sched_getscheduler:
1396
case __NR_sched_setscheduler: {
1397
Arg<pid_t> pid(0);
1398
return If(pid == 0, Allow()).Else(Trap(SchedTrap, nullptr));
1399
}
1400
1401
// For clock(3) on older glibcs; bug 1304220.
1402
case __NR_times:
1403
return Allow();
1404
1405
// Bug 1372428
1406
case __NR_uname:
1407
return Trap(UnameTrap, nullptr);
1408
CASES_FOR_fcntl:
1409
return Trap(FcntlTrap, nullptr);
1410
1411
default:
1412
return SandboxPolicyCommon::EvaluateSyscall(sysno);
1413
}
1414
}
1415
};
1416
1417
UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(
1418
const SandboxOpenedFiles* aFiles) {
1419
return UniquePtr<sandbox::bpf_dsl::Policy>(new GMPSandboxPolicy(aFiles));
1420
}
1421
1422
// The policy for the data decoder process is similar to the one for
1423
// media plugins, but the codec code is all in-tree so it's better
1424
// behaved and doesn't need special exceptions (or the ability to load
1425
// a plugin file). However, it does directly create shared memory
1426
// segments, so it may need file brokering.
1427
class RDDSandboxPolicy final : public SandboxPolicyCommon {
1428
public:
1429
explicit RDDSandboxPolicy(SandboxBrokerClient* aBroker)
1430
: SandboxPolicyCommon(aBroker) {}
1431
1432
static intptr_t FcntlTrap(const sandbox::arch_seccomp_data& aArgs,
1433
void* aux) {
1434
const auto cmd = static_cast<int>(aArgs.args[1]);
1435
switch (cmd) {
1436
// This process can't exec, so the actual close-on-exec flag
1437
// doesn't matter; have it always read as true and ignore writes.
1438
case F_GETFD:
1439
return O_CLOEXEC;
1440
case F_SETFD:
1441
return 0;
1442
default:
1443
return -ENOSYS;
1444
}
1445
}
1446
1447
ResultExpr EvaluateSyscall(int sysno) const override {
1448
switch (sysno) {
1449
case __NR_getrusage:
1450
return Allow();
1451
1452
CASES_FOR_fcntl:
1453
return Trap(FcntlTrap, nullptr);
1454
1455
// Pass through the common policy.
1456
default:
1457
return SandboxPolicyCommon::EvaluateSyscall(sysno);
1458
}
1459
}
1460
};
1461
1462
UniquePtr<sandbox::bpf_dsl::Policy> GetDecoderSandboxPolicy(
1463
SandboxBrokerClient* aMaybeBroker) {
1464
return UniquePtr<sandbox::bpf_dsl::Policy>(
1465
new RDDSandboxPolicy(aMaybeBroker));
1466
}
1467
1468
} // namespace mozilla