David Benjamin | 3e4dfbb | 2020-04-21 17:29:50 -0400 | [diff] [blame] | 1 | # Using BoringSSL in a Sandbox |
| 2 | |
| 3 | Sandboxes are a valuable tool for securing applications, so BoringSSL aims to |
| 4 | support them. However, it is difficult to make concrete API guarantees with |
| 5 | sandboxes. Sandboxes remove low-level OS resources and system calls, which |
| 6 | breaks platform abstractions. A syscall-filtering sandbox may, for instance, be |
| 7 | sensitive to otherwise non-breaking changes to use newer syscalls |
| 8 | in either BoringSSL or the C library. |
| 9 | |
| 10 | Some functions in BoringSSL, such as `BIO_new_file`, inherently need OS |
| 11 | resources like the filesystem. We assume that sandboxed consumers either avoid |
| 12 | those functions or make necessary resources available. Other functions like |
| 13 | `RSA_sign` are purely computational, but still have some baseline OS |
| 14 | dependencies. |
| 15 | |
| 16 | Sandboxes which drop privileges partway through a process's lifetime are |
| 17 | additionally sensitive to OS resources retained across the transitions. For |
| 18 | instance, if a library function internally opened and retained a handle to the |
| 19 | user's home directory, and then the application called `chroot`, that handle |
| 20 | would be a sandbox escape. |
| 21 | |
| 22 | This document attempts to describe these baseline OS dependencies and long-lived |
| 23 | internal resources. These dependencies may change over time, but we aim to |
David Benjamin | 90004f0 | 2023-11-30 13:10:17 -0500 | [diff] [blame] | 24 | [work with sandboxed consumers](./BREAKING-CHANGES.md) when they do. However, |
David Benjamin | 3e4dfbb | 2020-04-21 17:29:50 -0400 | [diff] [blame] | 25 | each sandbox imposes different constraints, so, above all, sandboxed consumers |
| 26 | must have ample test coverage to detect issues as they arise. |
| 27 | |
| 28 | ## Baseline dependencies |
| 29 | |
| 30 | Callers must assume that any BoringSSL function may perform one of the following |
| 31 | operations: |
| 32 | |
| 33 | ### Memory allocation |
| 34 | |
| 35 | Any BoringSSL function may allocate memory via `malloc` and related functions. |
| 36 | |
| 37 | ### Thread synchronization |
| 38 | |
| 39 | Any BoringSSL function may call into the platform's thread synchronization |
| 40 | primitives, including read/write locks and the equivalent of `pthread_once`. |
| 41 | These must succeed, or BoringSSL will abort the process. Callers, however, can |
| 42 | assume that BoringSSL functions will not spawn internal threads, unless |
| 43 | otherwise documented. |
| 44 | |
| 45 | Syscall-filtering sandboxes should note that BoringSSL uses `pthread_rwlock_t` |
| 46 | on POSIX systems, which is less common and may not be part of other libraries' |
| 47 | syscall surface. Additionally, thread synchronization primitives usually have an |
| 48 | atomics-based fast path. If a sandbox blocks a necessary pthreads syscall, it |
| 49 | may not show up in testing without lock contention. |
| 50 | |
| 51 | ### Standard error |
| 52 | |
| 53 | Any BoringSSL function may write to `stderr` or file descriptor |
| 54 | `STDERR_FILENO` (2), either via `FILE` APIs or low-level functions like `write`. |
| 55 | Writes to `stderr` may fail, but there must some file at `STDERR_FILENO` which |
| 56 | will tolerate error messages from BoringSSL. (The file descriptor must be |
| 57 | allocated so calls to `open` do not accidentally open something else there.) |
| 58 | |
| 59 | Note some C standard library implementations also log to `stderr`, so callers |
| 60 | should ensure this regardless. |
| 61 | |
| 62 | ### Entropy |
| 63 | |
| 64 | Any BoringSSL function may draw entropy from the OS. On Windows, this uses |
| 65 | `RtlGenRandom` and, on POSIX systems, this uses `getrandom`, `getentropy`, or a |
| 66 | `read` from a file descriptor to `/dev/urandom`. These operations must succeed |
David Benjamin | 7b31d69 | 2020-05-18 14:01:29 -0400 | [diff] [blame] | 67 | or BoringSSL will abort the process. BoringSSL only probes for `getrandom` |
| 68 | support once and assumes support is consistent for the lifetime of the address |
| 69 | space (and any copies made via `fork`). If a syscall-filtering sandbox is |
| 70 | enabled partway through this lifetime and changes whether `getrandom` works, |
| 71 | BoringSSL may abort the process. Sandboxes are recommended to allow |
| 72 | `getrandom`. |
David Benjamin | 3e4dfbb | 2020-04-21 17:29:50 -0400 | [diff] [blame] | 73 | |
| 74 | Note even deterministic algorithms may require OS entropy. For example, |
| 75 | RSASSA-PKCS1-v1_5 is deterministic, but BoringSSL draws entropy to implement |
| 76 | RSA blinding. |
| 77 | |
| 78 | Entropy gathering additionally has some initialization dependencies described in |
| 79 | the following section. |
| 80 | |
| 81 | ## Initialization |
| 82 | |
| 83 | BoringSSL has some uncommon OS dependencies which are only used once to |
| 84 | initialize some state. Sandboxes which drop privileges after some setup work may |
| 85 | use `CRYPTO_pre_sandbox_init` to initialize this state ahead of time. Otherwise, |
| 86 | callers must assume any BoringSSL function may depend on these resources, in |
| 87 | addition to the operations above. |
| 88 | |
| 89 | ### CPU capabilities |
| 90 | |
| 91 | On Linux ARM platforms, BoringSSL depends on OS APIs to query CPU capabilities. |
| 92 | 32-bit and 64-bit ARM both depend on the `getauxval` function. 32-bit ARM, to |
David Benjamin | 74a75b3 | 2023-05-18 19:20:27 -0400 | [diff] [blame] | 93 | work around bugs in older Android devices, may additionally read |
| 94 | `/proc/cpuinfo`. |
| 95 | |
| 96 | On 64-bit Apple ARM platforms, BoringSSL needs to query `hw.optional.*` sysctls. |
David Benjamin | 3e4dfbb | 2020-04-21 17:29:50 -0400 | [diff] [blame] | 97 | |
| 98 | If querying CPU capabilities fails, BoringSSL will still function, but may not |
| 99 | perform as well. |
| 100 | |
| 101 | ### Entropy |
| 102 | |
| 103 | On Linux systems without a working `getrandom`, drawing entropy from the OS |
| 104 | additionally requires opening `/dev/urandom`. If this fails, BoringSSL will |
| 105 | abort the process. BoringSSL retains the resulting file descriptor, even across |
| 106 | privilege transitions. |
| 107 | |
| 108 | ### Fork protection |
| 109 | |
| 110 | On Linux, BoringSSL allocates a page and calls `madvise` with `MADV_WIPEONFORK` |
| 111 | to protect single-use state from `fork`. This operation must not crash, but if |
| 112 | it fails, BoringSSL will use alternate fork-safety strategies, potentially at a |
| 113 | performance cost. If it succeeds, BoringSSL assumes `MADV_WIPEONFORK` is |
| 114 | functional and relies on it for fork-safety. Sandboxes must not report success |
| 115 | if they ignore the `MADV_WIPEONFORK` flag. As of writing, QEMU will ignore |
| 116 | `madvise` calls and report success, so BoringSSL detects this by calling |
| 117 | `madvise` with -1. Sandboxes must cleanly report an error instead of crashing. |
| 118 | |
| 119 | Once initialized, this mechanism does not require system calls in the steady |
| 120 | state, though note the configured page will be inherited across privilege |
| 121 | transitions. |
| 122 | |
| 123 | ## C and C++ standard library |
| 124 | |
| 125 | BoringSSL depends on the C and C++ standard libraries which, themselves, do not |
| 126 | make any guarantees about sandboxes. If it produces the correct answer and has |
| 127 | no observable invalid side effects, it is possible, though unreasonable, for |
| 128 | `memcmp` to create and close a socket. |
| 129 | |
| 130 | BoringSSL assumes that functions in the C and C++ library only have the platform |
| 131 | dependencies which would be "reasonable". For instance, a function in BoringSSL |
| 132 | which aims not to open files will still freely call any libc memory and |
| 133 | string functions. |
| 134 | |
| 135 | Note some C functions, such as `strerror`, may read files relating to the user's |
| 136 | locale. BoringSSL may trigger these paths and assumes the sandbox environment |
| 137 | will tolerate this. BoringSSL additionally cannot make guarantees about which |
| 138 | system calls are used by standard library's syscall wrappers. In some cases, the |
| 139 | compiler may add dependencies. (Some C++ language features emit locking code.) |
| 140 | Syscall-filtering sandboxes may need updates as these dependencies change. |