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 "Sandbox.h"
8 
9 #include "LinuxSched.h"
10 #include "SandboxBrokerClient.h"
11 #include "SandboxChrootProto.h"
12 #include "SandboxFilter.h"
13 #include "SandboxInternal.h"
14 #include "SandboxLogging.h"
15 #ifdef MOZ_GMP_SANDBOX
16 #include "SandboxOpenedFiles.h"
17 #endif
18 #include "SandboxReporterClient.h"
19 
20 #include <dirent.h>
21 #ifdef NIGHTLY_BUILD
22 #include "dlfcn.h"
23 #endif
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <linux/futex.h>
27 #include <pthread.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/prctl.h>
33 #include <sys/ptrace.h>
34 #include <sys/syscall.h>
35 #include <sys/time.h>
36 #include <unistd.h>
37 
38 #include "mozilla/Array.h"
39 #include "mozilla/Atomics.h"
40 #include "mozilla/Range.h"
41 #include "mozilla/SandboxInfo.h"
42 #include "mozilla/Span.h"
43 #include "mozilla/UniquePtr.h"
44 #include "mozilla/Unused.h"
45 #include "prenv.h"
46 #include "base/posix/eintr_wrapper.h"
47 #include "sandbox/linux/bpf_dsl/codegen.h"
48 #include "sandbox/linux/bpf_dsl/dump_bpf.h"
49 #include "sandbox/linux/bpf_dsl/policy.h"
50 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
51 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
52 #include "sandbox/linux/seccomp-bpf/trap.h"
53 #include "sandbox/linux/system_headers/linux_filter.h"
54 #include "sandbox/linux/system_headers/linux_seccomp.h"
55 #include "sandbox/linux/system_headers/linux_syscalls.h"
56 #if defined(ANDROID)
57 #include "sandbox/linux/system_headers/linux_ucontext.h"
58 #endif
59 
60 #ifdef MOZ_ASAN
61 // Copy libsanitizer declarations to avoid depending on ASAN headers.
62 // See also bug 1081242 comment #4.
63 extern "C" {
64 namespace __sanitizer {
65 // Win64 uses long long, but this is Linux.
66 typedef signed long sptr;
67 }  // namespace __sanitizer
68 
69 typedef struct {
70   int coverage_sandboxed;
71   __sanitizer::sptr coverage_fd;
72   unsigned int coverage_max_block_size;
73 } __sanitizer_sandbox_arguments;
74 
75 MOZ_IMPORT_API void __sanitizer_sandbox_on_notify(
76     __sanitizer_sandbox_arguments* args);
77 }  // extern "C"
78 #endif  // MOZ_ASAN
79 
80 // Signal number used to enable seccomp on each thread.
81 mozilla::Atomic<int> gSeccompTsyncBroadcastSignum(0);
82 
83 namespace mozilla {
84 
85 static bool gSandboxCrashOnError = false;
86 
87 // This is initialized by SandboxSetCrashFunc().
88 SandboxCrashFunc gSandboxCrashFunc;
89 
90 static SandboxReporterClient* gSandboxReporterClient;
91 static void (*gChromiumSigSysHandler)(int, siginfo_t*, void*);
92 
93 // Test whether a ucontext, interpreted as the state after a syscall,
94 // indicates the given error.  See also sandbox::Syscall::PutValueInUcontext.
ContextIsError(const ucontext_t * aContext,int aError)95 static bool ContextIsError(const ucontext_t* aContext, int aError) {
96   // Avoid integer promotion warnings.  (The unary addition makes
97   // the decltype not evaluate to a reference type.)
98   typedef decltype(+SECCOMP_RESULT(aContext)) reg_t;
99 
100 #ifdef __mips__
101   return SECCOMP_PARM4(aContext) != 0 &&
102          SECCOMP_RESULT(aContext) == static_cast<reg_t>(aError);
103 #else
104   return SECCOMP_RESULT(aContext) == static_cast<reg_t>(-aError);
105 #endif
106 }
107 
108 /**
109  * This is the SIGSYS handler function.  It delegates to the Chromium
110  * TrapRegistry handler (see InstallSigSysHandler, below) and, if the
111  * trap handler installed by the policy would fail with ENOSYS,
112  * crashes the process.  This allows unintentional policy failures to
113  * be reported as crash dumps and fixed.  It also logs information
114  * about the failed system call.
115  *
116  * Note that this could be invoked in parallel on multiple threads and
117  * that it could be in async signal context (e.g., intercepting an
118  * open() called from an async signal handler).
119  */
SigSysHandler(int nr,siginfo_t * info,void * void_context)120 static void SigSysHandler(int nr, siginfo_t* info, void* void_context) {
121   ucontext_t* ctx = static_cast<ucontext_t*>(void_context);
122   // This shouldn't ever be null, but the Chromium handler checks for
123   // that and refrains from crashing, so let's not crash release builds:
124   MOZ_DIAGNOSTIC_ASSERT(ctx);
125   if (!ctx) {
126     return;
127   }
128 
129   // Save a copy of the context before invoking the trap handler,
130   // which will overwrite one or more registers with the return value.
131   ucontext_t savedCtx = *ctx;
132 
133   gChromiumSigSysHandler(nr, info, ctx);
134   if (!ContextIsError(ctx, ENOSYS)) {
135     return;
136   }
137 
138   SandboxReport report = gSandboxReporterClient->MakeReportAndSend(&savedCtx);
139 
140   // TODO, someday when this is enabled on MIPS: include the two extra
141   // args in the error message.
142   SANDBOX_LOG_ERROR(
143       "seccomp sandbox violation: pid %d, tid %d, syscall %d,"
144       " args %d %d %d %d %d %d.%s",
145       report.mPid, report.mTid, report.mSyscall, report.mArgs[0],
146       report.mArgs[1], report.mArgs[2], report.mArgs[3], report.mArgs[4],
147       report.mArgs[5], gSandboxCrashOnError ? "  Killing process." : "");
148 
149   if (gSandboxCrashOnError) {
150     // Bug 1017393: record syscall number somewhere useful.
151     info->si_addr = reinterpret_cast<void*>(report.mSyscall);
152 
153     gSandboxCrashFunc(nr, info, &savedCtx);
154     _exit(127);
155   }
156 }
157 
158 /**
159  * This function installs the SIGSYS handler.  This is slightly
160  * complicated because we want to use Chromium's handler to dispatch
161  * to specific trap handlers defined in the policy, but we also need
162  * the full original signal context to give to Breakpad for crash
163  * dumps.  So we install Chromium's handler first, then retrieve its
164  * address so our replacement can delegate to it.
165  */
InstallSigSysHandler(void)166 static void InstallSigSysHandler(void) {
167   struct sigaction act;
168 
169   // Ensure that the Chromium handler is installed.
170   Unused << sandbox::Trap::Registry();
171 
172   // If the signal handling state isn't as expected, crash now instead
173   // of crashing later (and more confusingly) when SIGSYS happens.
174 
175   if (sigaction(SIGSYS, nullptr, &act) != 0) {
176     MOZ_CRASH("Couldn't read old SIGSYS disposition");
177   }
178   if ((act.sa_flags & SA_SIGINFO) != SA_SIGINFO) {
179     MOZ_CRASH("SIGSYS not already set to a siginfo handler?");
180   }
181   MOZ_RELEASE_ASSERT(act.sa_sigaction);
182   gChromiumSigSysHandler = act.sa_sigaction;
183   act.sa_sigaction = SigSysHandler;
184   // Currently, SA_NODEFER should already be set by the Chromium code,
185   // but it's harmless to ensure that it's set:
186   MOZ_ASSERT(act.sa_flags & SA_NODEFER);
187   act.sa_flags |= SA_NODEFER;
188   if (sigaction(SIGSYS, &act, nullptr) < 0) {
189     MOZ_CRASH("Couldn't change SIGSYS disposition");
190   }
191 }
192 
193 /**
194  * This function installs the syscall filter, a.k.a. seccomp.  The
195  * aUseTSync flag indicates whether this should apply to all threads
196  * in the process -- which will fail if the kernel doesn't support
197  * that -- or only the current thread.
198  *
199  * SECCOMP_MODE_FILTER is the "bpf" mode of seccomp which allows
200  * to pass a bpf program (in our case, it contains a syscall
201  * whitelist).
202  *
203  * PR_SET_NO_NEW_PRIVS ensures that it is impossible to grant more
204  * syscalls to the process beyond this point (even after fork()), and
205  * prevents gaining capabilities (e.g., by exec'ing a setuid root
206  * program).  The kernel won't allow seccomp-bpf without doing this,
207  * because otherwise it could be used for privilege escalation attacks.
208  *
209  * Returns false if the filter was already installed (see the
210  * PR_SET_NO_NEW_PRIVS rule in SandboxFilter.cpp).  Crashes on any
211  * other error condition.
212  *
213  * @see SandboxInfo
214  * @see BroadcastSetThreadSandbox
215  */
InstallSyscallFilter(const sock_fprog * aProg,bool aUseTSync)216 static bool MOZ_MUST_USE InstallSyscallFilter(const sock_fprog* aProg,
217                                               bool aUseTSync) {
218   if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
219     if (!aUseTSync && errno == ETXTBSY) {
220       return false;
221     }
222     SANDBOX_LOG_ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %s", strerror(errno));
223     MOZ_CRASH("prctl(PR_SET_NO_NEW_PRIVS)");
224   }
225 
226   if (aUseTSync) {
227     if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
228                 SECCOMP_FILTER_FLAG_TSYNC, aProg) != 0) {
229       SANDBOX_LOG_ERROR("thread-synchronized seccomp failed: %s",
230                         strerror(errno));
231       MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
232     }
233   } else {
234     if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)aProg, 0,
235               0)) {
236       SANDBOX_LOG_ERROR("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) failed: %s",
237                         strerror(errno));
238       MOZ_CRASH("seccomp+tsync failed, but kernel supports tsync");
239     }
240   }
241   return true;
242 }
243 
244 // Use signals for permissions that need to be set per-thread.
245 // The communication channel from the signal handler back to the main thread.
246 static mozilla::Atomic<int> gSetSandboxDone;
247 // Pass the filter itself through a global.
248 const sock_fprog* gSetSandboxFilter;
249 
250 // We have to dynamically allocate the signal number; see bug 1038900.
251 // This function returns the first realtime signal currently set to
252 // default handling (i.e., not in use), or 0 if none could be found.
253 //
254 // WARNING: if this function or anything similar to it (including in
255 // external libraries) is used on multiple threads concurrently, there
256 // will be a race condition.
FindFreeSignalNumber()257 static int FindFreeSignalNumber() {
258   for (int signum = SIGRTMAX; signum >= SIGRTMIN; --signum) {
259     struct sigaction sa;
260 
261     if (sigaction(signum, nullptr, &sa) == 0 &&
262         (sa.sa_flags & SA_SIGINFO) == 0 && sa.sa_handler == SIG_DFL) {
263       return signum;
264     }
265   }
266   return 0;
267 }
268 
269 // Returns true if sandboxing was enabled, or false if sandboxing
270 // already was enabled.  Crashes if sandboxing could not be enabled.
SetThreadSandbox()271 static bool SetThreadSandbox() {
272   return InstallSyscallFilter(gSetSandboxFilter, false);
273 }
274 
SetThreadSandboxHandler(int signum)275 static void SetThreadSandboxHandler(int signum) {
276   // The non-zero number sent back to the main thread indicates
277   // whether action was taken.
278   if (SetThreadSandbox()) {
279     gSetSandboxDone = 2;
280   } else {
281     gSetSandboxDone = 1;
282   }
283   // Wake up the main thread.  See the FUTEX_WAIT call, below, for an
284   // explanation.
285   syscall(__NR_futex, reinterpret_cast<int*>(&gSetSandboxDone), FUTEX_WAKE, 1);
286 }
287 
EnterChroot()288 static void EnterChroot() {
289   if (!PR_GetEnv(kSandboxChrootEnvFlag)) {
290     return;
291   }
292   char msg = kSandboxChrootRequest;
293   ssize_t msg_len = HANDLE_EINTR(write(kSandboxChrootClientFd, &msg, 1));
294   MOZ_RELEASE_ASSERT(msg_len == 1);
295   msg_len = HANDLE_EINTR(read(kSandboxChrootClientFd, &msg, 1));
296   MOZ_RELEASE_ASSERT(msg_len == 1);
297   MOZ_RELEASE_ASSERT(msg == kSandboxChrootResponse);
298   close(kSandboxChrootClientFd);
299 }
300 
BroadcastSetThreadSandbox(const sock_fprog * aFilter)301 static void BroadcastSetThreadSandbox(const sock_fprog* aFilter) {
302   pid_t pid, tid, myTid;
303   DIR* taskdp;
304   struct dirent* de;
305 
306   // This function does not own *aFilter, so this global needs to
307   // always be zeroed before returning.
308   gSetSandboxFilter = aFilter;
309 
310   static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
311                 "mozilla::Atomic<int> isn't represented by an int");
312   pid = getpid();
313   myTid = syscall(__NR_gettid);
314   taskdp = opendir("/proc/self/task");
315   if (taskdp == nullptr) {
316     SANDBOX_LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
317     MOZ_CRASH();
318   }
319 
320   // In case this races with a not-yet-deprivileged thread cloning
321   // itself, repeat iterating over all threads until we find none
322   // that are still privileged.
323   bool sandboxProgress;
324   const int tsyncSignum = gSeccompTsyncBroadcastSignum;
325   do {
326     sandboxProgress = false;
327     // For each thread...
328     while ((de = readdir(taskdp))) {
329       char* endptr;
330       tid = strtol(de->d_name, &endptr, 10);
331       if (*endptr != '\0' || tid <= 0) {
332         // Not a task ID.
333         continue;
334       }
335       if (tid == myTid) {
336         // Drop this thread's privileges last, below, so we can
337         // continue to signal other threads.
338         continue;
339       }
340 
341       MOZ_RELEASE_ASSERT(tsyncSignum != 0);
342 
343       // Reset the futex cell and signal.
344       gSetSandboxDone = 0;
345       if (syscall(__NR_tgkill, pid, tid, tsyncSignum) != 0) {
346         if (errno == ESRCH) {
347           SANDBOX_LOG_ERROR("Thread %d unexpectedly exited.", tid);
348           // Rescan threads, in case it forked before exiting.
349           sandboxProgress = true;
350           continue;
351         }
352         SANDBOX_LOG_ERROR("tgkill(%d,%d): %s\n", pid, tid, strerror(errno));
353         MOZ_CRASH();
354       }
355       // It's unlikely, but if the thread somehow manages to exit
356       // after receiving the signal but before entering the signal
357       // handler, we need to avoid blocking forever.
358       //
359       // Using futex directly lets the signal handler send the wakeup
360       // from an async signal handler (pthread mutex/condvar calls
361       // aren't allowed), and to use a relative timeout that isn't
362       // affected by changes to the system clock (not possible with
363       // POSIX semaphores).
364       //
365       // If a thread doesn't respond within a reasonable amount of
366       // time, but still exists, we crash -- the alternative is either
367       // blocking forever or silently losing security, and it
368       // shouldn't actually happen.
369       static const int crashDelay = 10;  // seconds
370       struct timespec timeLimit;
371       clock_gettime(CLOCK_MONOTONIC, &timeLimit);
372       timeLimit.tv_sec += crashDelay;
373       while (true) {
374         static const struct timespec futexTimeout = {0,
375                                                      10 * 1000 * 1000};  // 10ms
376         // Atomically: if gSetSandboxDone == 0, then sleep.
377         if (syscall(__NR_futex, reinterpret_cast<int*>(&gSetSandboxDone),
378                     FUTEX_WAIT, 0, &futexTimeout) != 0) {
379           if (errno != EWOULDBLOCK && errno != ETIMEDOUT && errno != EINTR) {
380             SANDBOX_LOG_ERROR("FUTEX_WAIT: %s\n", strerror(errno));
381             MOZ_CRASH();
382           }
383         }
384         // Did the handler finish?
385         if (gSetSandboxDone > 0) {
386           if (gSetSandboxDone == 2) {
387             sandboxProgress = true;
388           }
389           break;
390         }
391         // Has the thread ceased to exist?
392         if (syscall(__NR_tgkill, pid, tid, 0) != 0) {
393           if (errno == ESRCH) {
394             SANDBOX_LOG_ERROR("Thread %d unexpectedly exited.", tid);
395           }
396           // Rescan threads, in case it forked before exiting.
397           // Also, if it somehow failed in a way that wasn't ESRCH,
398           // and still exists, that will be handled on the next pass.
399           sandboxProgress = true;
400           break;
401         }
402         struct timespec now;
403         clock_gettime(CLOCK_MONOTONIC, &now);
404         if (now.tv_sec > timeLimit.tv_sec ||
405             (now.tv_sec == timeLimit.tv_sec &&
406              now.tv_nsec > timeLimit.tv_nsec)) {
407           SANDBOX_LOG_ERROR(
408               "Thread %d unresponsive for %d seconds."
409               "  Killing process.",
410               tid, crashDelay);
411           MOZ_CRASH();
412         }
413       }
414     }
415     rewinddir(taskdp);
416   } while (sandboxProgress);
417 
418   void (*oldHandler)(int);
419   oldHandler = signal(tsyncSignum, SIG_DFL);
420   if (oldHandler != SetThreadSandboxHandler) {
421     // See the comment on FindFreeSignalNumber about race conditions.
422     SANDBOX_LOG_ERROR("handler for signal %d was changed to %p!", tsyncSignum,
423                       oldHandler);
424     MOZ_CRASH();
425   }
426   gSeccompTsyncBroadcastSignum = 0;
427   Unused << closedir(taskdp);
428   // And now, deprivilege the main thread:
429   SetThreadSandbox();
430   gSetSandboxFilter = nullptr;
431 }
432 
ApplySandboxWithTSync(sock_fprog * aFilter)433 static void ApplySandboxWithTSync(sock_fprog* aFilter) {
434   // At this point we're committed to using tsync, because we'd have
435   // needed to allocate a signal and prevent it from being blocked on
436   // other threads (see SandboxHooks.cpp), so there's no attempt to
437   // fall back to the non-tsync path.
438   if (!InstallSyscallFilter(aFilter, true)) {
439     MOZ_CRASH();
440   }
441 }
442 
443 #ifdef NIGHTLY_BUILD
IsLibPresent(const char * aName)444 static bool IsLibPresent(const char* aName) {
445   if (const auto handle = dlopen(aName, RTLD_LAZY | RTLD_NOLOAD)) {
446     dlclose(handle);
447     return true;
448   }
449   return false;
450 }
451 
452 static const Array<const char*, 1> kLibsThatWillCrash{
453     "libesets_pac.so",
454 };
455 #endif  // NIGHTLY_BUILD
456 
SandboxEarlyInit()457 void SandboxEarlyInit() {
458   if (PR_GetEnv("MOZ_SANDBOXED") == nullptr) {
459     return;
460   }
461 
462   // Fix LD_PRELOAD for any child processes.  See bug 1434392 comment #10;
463   // this can probably go away when audio remoting is mandatory.
464   const char* oldPreload = PR_GetEnv("MOZ_ORIG_LD_PRELOAD");
465   char* preloadEntry;
466   // This string is "leaked" because the environment takes ownership.
467   if (asprintf(&preloadEntry, "LD_PRELOAD=%s", oldPreload ? oldPreload : "") !=
468       -1) {
469     PR_SetEnv(preloadEntry);
470   }
471 
472   // If TSYNC is not supported, set up signal handler
473   // used to enable seccomp on each thread.
474   if (!SandboxInfo::Get().Test(SandboxInfo::kHasSeccompTSync)) {
475     // The signal number has to be chosen early, so that the
476     // interceptions in SandboxHooks.cpp can prevent it from being
477     // masked.
478     const int tsyncSignum = FindFreeSignalNumber();
479     if (tsyncSignum == 0) {
480       SANDBOX_LOG_ERROR("No available signal numbers!");
481       MOZ_CRASH();
482     }
483     gSeccompTsyncBroadcastSignum = tsyncSignum;
484 
485     // ...and the signal handler also needs to be installed now, to
486     // indicate to anything else looking for free signals that it's
487     // claimed.
488     void (*oldHandler)(int);
489     oldHandler = signal(tsyncSignum, SetThreadSandboxHandler);
490     if (oldHandler != SIG_DFL) {
491       // See the comment on FindFreeSignalNumber about race conditions.
492       SANDBOX_LOG_ERROR("signal %d in use by handler %p!\n", tsyncSignum,
493                         oldHandler);
494       MOZ_CRASH();
495     }
496   }
497 }
498 
SandboxLateInit()499 static void SandboxLateInit() {
500 #ifdef NIGHTLY_BUILD
501   gSandboxCrashOnError = true;
502   for (const char* name : kLibsThatWillCrash) {
503     if (IsLibPresent(name)) {
504       gSandboxCrashOnError = false;
505       break;
506     }
507   }
508 #endif
509 
510   if (const char* envVar = PR_GetEnv("MOZ_SANDBOX_CRASH_ON_ERROR")) {
511     if (envVar[0]) {
512       gSandboxCrashOnError = envVar[0] != '0';
513     }
514   }
515 }
516 
517 // Common code for sandbox startup.
SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy)518 static void SetCurrentProcessSandbox(
519     UniquePtr<sandbox::bpf_dsl::Policy> aPolicy) {
520   MOZ_ASSERT(gSandboxCrashFunc);
521   MOZ_RELEASE_ASSERT(gSandboxReporterClient != nullptr);
522   SandboxLateInit();
523 
524   // Auto-collect child processes -- mainly the chroot helper if
525   // present, but also anything setns()ed into the pid namespace (not
526   // yet implemented).  This process won't be able to waitpid them
527   // after the seccomp-bpf policy is applied.
528   signal(SIGCHLD, SIG_IGN);
529 
530   // Note: PolicyCompiler borrows the policy and registry for its
531   // lifetime, but does not take ownership of them.
532   sandbox::bpf_dsl::PolicyCompiler compiler(aPolicy.get(),
533                                             sandbox::Trap::Registry());
534   sandbox::CodeGen::Program program = compiler.Compile();
535   if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
536     sandbox::bpf_dsl::DumpBPF::PrintProgram(program);
537   }
538 
539   InstallSigSysHandler();
540 
541 #ifdef MOZ_ASAN
542   __sanitizer_sandbox_arguments asanArgs;
543   asanArgs.coverage_sandboxed = 1;
544   asanArgs.coverage_fd = -1;
545   asanArgs.coverage_max_block_size = 0;
546   __sanitizer_sandbox_on_notify(&asanArgs);
547 #endif
548 
549   // The syscall takes a C-style array, so copy the vector into one.
550   size_t programLen = program.size();
551   UniquePtr<sock_filter[]> flatProgram(new sock_filter[programLen]);
552   for (auto i = program.begin(); i != program.end(); ++i) {
553     flatProgram[i - program.begin()] = *i;
554   }
555 
556   sock_fprog fprog;
557   fprog.filter = flatProgram.get();
558   fprog.len = static_cast<unsigned short>(programLen);
559   MOZ_RELEASE_ASSERT(static_cast<size_t>(fprog.len) == programLen);
560 
561   const SandboxInfo info = SandboxInfo::Get();
562   if (info.Test(SandboxInfo::kHasSeccompTSync)) {
563     if (info.Test(SandboxInfo::kVerbose)) {
564       SANDBOX_LOG_ERROR("using seccomp tsync");
565     }
566     ApplySandboxWithTSync(&fprog);
567   } else {
568     if (info.Test(SandboxInfo::kVerbose)) {
569       SANDBOX_LOG_ERROR("no tsync support; using signal broadcast");
570     }
571     BroadcastSetThreadSandbox(&fprog);
572   }
573 
574   // Now that all threads' filesystem accesses are being intercepted
575   // (if a broker is used) it's safe to chroot the process:
576   EnterChroot();
577 }
578 
579 #ifdef MOZ_CONTENT_SANDBOX
580 /**
581  * Starts the seccomp sandbox for a content process.  Should be called
582  * only once, and before any potentially harmful content is loaded.
583  *
584  * Will normally make the process exit on failure.
585  */
SetContentProcessSandbox(ContentProcessSandboxParams && aParams)586 bool SetContentProcessSandbox(ContentProcessSandboxParams&& aParams) {
587   int brokerFd = aParams.mBrokerFd;
588   aParams.mBrokerFd = -1;
589 
590   if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForContent)) {
591     if (brokerFd >= 0) {
592       close(brokerFd);
593     }
594     return false;
595   }
596 
597   auto procType = aParams.mFileProcess ? SandboxReport::ProcType::FILE
598                                        : SandboxReport::ProcType::CONTENT;
599   gSandboxReporterClient = new SandboxReporterClient(procType);
600 
601   // This needs to live until the process exits.
602   static SandboxBrokerClient* sBroker;
603   if (brokerFd >= 0) {
604     sBroker = new SandboxBrokerClient(brokerFd);
605   }
606 
607   SetCurrentProcessSandbox(GetContentSandboxPolicy(sBroker, Move(aParams)));
608   return true;
609 }
610 #endif  // MOZ_CONTENT_SANDBOX
611 
612 #ifdef MOZ_GMP_SANDBOX
613 /**
614  * Starts the seccomp sandbox for a media plugin process.  Should be
615  * called only once, and before any potentially harmful content is
616  * loaded -- including the plugin itself, if it's considered untrusted.
617  *
618  * The file indicated by aFilePath, if non-null, can be open()ed
619  * read-only, once, after the sandbox starts; it should be the .so
620  * file implementing the not-yet-loaded plugin.
621  *
622  * Will normally make the process exit on failure.
623  */
SetMediaPluginSandbox(const char * aFilePath)624 void SetMediaPluginSandbox(const char* aFilePath) {
625   MOZ_RELEASE_ASSERT(aFilePath != nullptr);
626   if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia)) {
627     return;
628   }
629 
630   gSandboxReporterClient =
631       new SandboxReporterClient(SandboxReport::ProcType::MEDIA_PLUGIN);
632 
633   SandboxOpenedFile plugin(aFilePath);
634   if (!plugin.IsOpen()) {
635     SANDBOX_LOG_ERROR("failed to open plugin file %s: %s", aFilePath,
636                       strerror(errno));
637     MOZ_CRASH();
638   }
639 
640   auto files = new SandboxOpenedFiles();
641   files->Add(Move(plugin));
642   files->Add("/dev/urandom", true);
643   files->Add("/sys/devices/system/cpu/cpu0/tsc_freq_khz");
644   files->Add("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
645   files->Add("/proc/cpuinfo");  // Info also available via CPUID instruction.
646 #ifdef __i386__
647   files->Add("/proc/self/auxv");  // Info also in process's address space.
648 #endif
649 
650   // Finally, start the sandbox.
651   SetCurrentProcessSandbox(GetMediaSandboxPolicy(files));
652 }
653 #endif  // MOZ_GMP_SANDBOX
654 
655 }  // namespace mozilla
656