Source Code Overview
The core of the Windows sandbox is Google's chromium sandbox. Relative to the root of mozilla-central, the sandbox exists at:
The chromium sandbox is based on the chromium base libraries (Google's code) which are located at:
There is also partial/shim code to get the base code compiling with our SDK build settings or to limit the base code by reducing dependencies at:
The chromium Windows sandbox itself (Google's code) is located at:
There are 2 processes when dealing with a sandboxed application:
- The broker: The parent process that starts sandboxed children
- The target: The child process that is sandboxed
Both processes make use of the chromium sandbox library, but they make use of it indirectly through 2 libraries (Mozilla code). This indirect use of the library is due to header conflicts with the ipc layer where it has a different, much older, non compatible, copy of the chromium base library (bug 925471):
- For the broker, ./security/sandbox/win/src/sandboxbroker
- For the target, ./security/sandbox/win/src/sandboxtarget
Key source code locations
Level descriptions header:
The call that starts the sandboxed process in Firefox is:
All of the code that sets policies can be found here:
The OSX sandbox is based on the TrustedBSD MAC Framework. It is undocumented and considered private by Apple.
Linux sandboxing technologies generally fall into two categories: those that act on the semantics of operations (e.g., what happens when a filesystem path is resolved) and those that affect raw system calls (e.g., what happens when syscall #83 is invoked). There's a more detailed explanation in the blog post announcing seccomp-bpf, which is the main syscall-filtering facility.
We're primarily using seccomp-bpf because it's the only thing that's available everywhere (>99% of the Linux Firefox userbase, at last count). There are some weaknesses to using only seccomp-bpf:
- The possibility of overlooking obscure corner cases, like unnamed datagram sockets, that could allow privilege escalation.
- The seccomp-bpf policy can act on argument values, but can't dereference pointer arguments, like the path to open(); in such cases it's necessary to intercept the syscall and message an unsandboxed broker to validate and perform the operation, which adds latency and attack surface.
Semantic isolation, like changing the filesystem root or creating a separate network stack with no access to the real network (unsharing the network namespace), has traditionally required superuser privileges. There are two ways to get around this: unprivileged user namespaces and a setuid-root helper executable.
We're using unprivileged user namespaces for additional security where available; they don't require any system-level setup, and 88% of Linux Firefoxes are on a kernel that supports them, according to telemetry. The reason we don't require it (as, for example, gaol does) is the other 12%: some distributions disable the feature because it has its own security risks. (Briefly: it makes subtle changes to authorization semantics, and it exposes kernel attack surface that's normally restricted to root; both of these have led to local privilege escalation vulnerabilities in the past.)
But shipping a setuid-root executable *also* doesn't work for everyone: we support downloading and running Firefox as a regular user, without having it installed as a system package. There are also some changes that would be needed to how we create child processes and set up IPC communication with them, and invoke the chroot helper; and it complicates testing. Chromium used this approach in 2009 because there was no other choice; they would prefer to remove it but don't seem to have a timeline for doing so.
At the time of this writing (June 2017), namespace sandboxing is used only for media plugins (EME CDMs and OpenH264): content processes can't use any of it at least until audio is remoted.