|
|
|
# Using BoringSSL in a Sandbox
|
|
|
|
|
|
|
|
Sandboxes are a valuable tool for securing applications, so BoringSSL aims to
|
|
|
|
support them. However, it is difficult to make concrete API guarantees with
|
|
|
|
sandboxes. Sandboxes remove low-level OS resources and system calls, which
|
|
|
|
breaks platform abstractions. A syscall-filtering sandbox may, for instance, be
|
|
|
|
sensitive to otherwise non-breaking changes to use newer syscalls
|
|
|
|
in either BoringSSL or the C library.
|
|
|
|
|
|
|
|
Some functions in BoringSSL, such as `BIO_new_file`, inherently need OS
|
|
|
|
resources like the filesystem. We assume that sandboxed consumers either avoid
|
|
|
|
those functions or make necessary resources available. Other functions like
|
|
|
|
`RSA_sign` are purely computational, but still have some baseline OS
|
|
|
|
dependencies.
|
|
|
|
|
|
|
|
Sandboxes which drop privileges partway through a process's lifetime are
|
|
|
|
additionally sensitive to OS resources retained across the transitions. For
|
|
|
|
instance, if a library function internally opened and retained a handle to the
|
|
|
|
user's home directory, and then the application called `chroot`, that handle
|
|
|
|
would be a sandbox escape.
|
|
|
|
|
|
|
|
This document attempts to describe these baseline OS dependencies and long-lived
|
|
|
|
internal resources. These dependencies may change over time, but we aim to
|
|
|
|
[work with sandboxed consumers](/BREAKING-CHANGES.md) when they do. However,
|
|
|
|
each sandbox imposes different constraints, so, above all, sandboxed consumers
|
|
|
|
must have ample test coverage to detect issues as they arise.
|
|
|
|
|
|
|
|
## Baseline dependencies
|
|
|
|
|
|
|
|
Callers must assume that any BoringSSL function may perform one of the following
|
|
|
|
operations:
|
|
|
|
|
|
|
|
### Memory allocation
|
|
|
|
|
|
|
|
Any BoringSSL function may allocate memory via `malloc` and related functions.
|
|
|
|
|
|
|
|
### Thread synchronization
|
|
|
|
|
|
|
|
Any BoringSSL function may call into the platform's thread synchronization
|
|
|
|
primitives, including read/write locks and the equivalent of `pthread_once`.
|
|
|
|
These must succeed, or BoringSSL will abort the process. Callers, however, can
|
|
|
|
assume that BoringSSL functions will not spawn internal threads, unless
|
|
|
|
otherwise documented.
|
|
|
|
|
|
|
|
Syscall-filtering sandboxes should note that BoringSSL uses `pthread_rwlock_t`
|
|
|
|
on POSIX systems, which is less common and may not be part of other libraries'
|
|
|
|
syscall surface. Additionally, thread synchronization primitives usually have an
|
|
|
|
atomics-based fast path. If a sandbox blocks a necessary pthreads syscall, it
|
|
|
|
may not show up in testing without lock contention.
|
|
|
|
|
|
|
|
### Standard error
|
|
|
|
|
|
|
|
Any BoringSSL function may write to `stderr` or file descriptor
|
|
|
|
`STDERR_FILENO` (2), either via `FILE` APIs or low-level functions like `write`.
|
|
|
|
Writes to `stderr` may fail, but there must some file at `STDERR_FILENO` which
|
|
|
|
will tolerate error messages from BoringSSL. (The file descriptor must be
|
|
|
|
allocated so calls to `open` do not accidentally open something else there.)
|
|
|
|
|
|
|
|
Note some C standard library implementations also log to `stderr`, so callers
|
|
|
|
should ensure this regardless.
|
|
|
|
|
|
|
|
### Entropy
|
|
|
|
|
|
|
|
Any BoringSSL function may draw entropy from the OS. On Windows, this uses
|
|
|
|
`RtlGenRandom` and, on POSIX systems, this uses `getrandom`, `getentropy`, or a
|
|
|
|
`read` from a file descriptor to `/dev/urandom`. These operations must succeed
|
|
|
|
or BoringSSL will abort the process. BoringSSL only probes for `getrandom`
|
|
|
|
support once and assumes support is consistent for the lifetime of the address
|
|
|
|
space (and any copies made via `fork`). If a syscall-filtering sandbox is
|
|
|
|
enabled partway through this lifetime and changes whether `getrandom` works,
|
|
|
|
BoringSSL may abort the process. Sandboxes are recommended to allow
|
|
|
|
`getrandom`.
|
|
|
|
|
|
|
|
Note even deterministic algorithms may require OS entropy. For example,
|
|
|
|
RSASSA-PKCS1-v1_5 is deterministic, but BoringSSL draws entropy to implement
|
|
|
|
RSA blinding.
|
|
|
|
|
|
|
|
Entropy gathering additionally has some initialization dependencies described in
|
|
|
|
the following section.
|
|
|
|
|
|
|
|
## Initialization
|
|
|
|
|
|
|
|
BoringSSL has some uncommon OS dependencies which are only used once to
|
|
|
|
initialize some state. Sandboxes which drop privileges after some setup work may
|
|
|
|
use `CRYPTO_pre_sandbox_init` to initialize this state ahead of time. Otherwise,
|
|
|
|
callers must assume any BoringSSL function may depend on these resources, in
|
|
|
|
addition to the operations above.
|
|
|
|
|
|
|
|
### CPU capabilities
|
|
|
|
|
|
|
|
On Linux ARM platforms, BoringSSL depends on OS APIs to query CPU capabilities.
|
|
|
|
32-bit and 64-bit ARM both depend on the `getauxval` function. 32-bit ARM, to
|
|
|
|
work around bugs in older Android devices, may additionally read
|
|
|
|
`/proc/cpuinfo`.
|
|
|
|
|
|
|
|
On 64-bit Apple ARM platforms, BoringSSL needs to query `hw.optional.*` sysctls.
|
|
|
|
|
|
|
|
If querying CPU capabilities fails, BoringSSL will still function, but may not
|
|
|
|
perform as well.
|
|
|
|
|
|
|
|
### Entropy
|
|
|
|
|
|
|
|
On Linux systems without a working `getrandom`, drawing entropy from the OS
|
|
|
|
additionally requires opening `/dev/urandom`. If this fails, BoringSSL will
|
|
|
|
abort the process. BoringSSL retains the resulting file descriptor, even across
|
|
|
|
privilege transitions.
|
|
|
|
|
|
|
|
### Fork protection
|
|
|
|
|
|
|
|
On Linux, BoringSSL allocates a page and calls `madvise` with `MADV_WIPEONFORK`
|
|
|
|
to protect single-use state from `fork`. This operation must not crash, but if
|
|
|
|
it fails, BoringSSL will use alternate fork-safety strategies, potentially at a
|
|
|
|
performance cost. If it succeeds, BoringSSL assumes `MADV_WIPEONFORK` is
|
|
|
|
functional and relies on it for fork-safety. Sandboxes must not report success
|
|
|
|
if they ignore the `MADV_WIPEONFORK` flag. As of writing, QEMU will ignore
|
|
|
|
`madvise` calls and report success, so BoringSSL detects this by calling
|
|
|
|
`madvise` with -1. Sandboxes must cleanly report an error instead of crashing.
|
|
|
|
|
|
|
|
Once initialized, this mechanism does not require system calls in the steady
|
|
|
|
state, though note the configured page will be inherited across privilege
|
|
|
|
transitions.
|
|
|
|
|
|
|
|
## C and C++ standard library
|
|
|
|
|
|
|
|
BoringSSL depends on the C and C++ standard libraries which, themselves, do not
|
|
|
|
make any guarantees about sandboxes. If it produces the correct answer and has
|
|
|
|
no observable invalid side effects, it is possible, though unreasonable, for
|
|
|
|
`memcmp` to create and close a socket.
|
|
|
|
|
|
|
|
BoringSSL assumes that functions in the C and C++ library only have the platform
|
|
|
|
dependencies which would be "reasonable". For instance, a function in BoringSSL
|
|
|
|
which aims not to open files will still freely call any libc memory and
|
|
|
|
string functions.
|
|
|
|
|
|
|
|
Note some C functions, such as `strerror`, may read files relating to the user's
|
|
|
|
locale. BoringSSL may trigger these paths and assumes the sandbox environment
|
|
|
|
will tolerate this. BoringSSL additionally cannot make guarantees about which
|
|
|
|
system calls are used by standard library's syscall wrappers. In some cases, the
|
|
|
|
compiler may add dependencies. (Some C++ language features emit locking code.)
|
|
|
|
Syscall-filtering sandboxes may need updates as these dependencies change.
|