|
| 1 | +# Memory Hardening |
| 2 | + |
| 3 | +While protecting against user-space memory attacks in the general case is not within the threat |
| 4 | +model for Bitwarden applications, the lock state must be protected, and it should not be possible to |
| 5 | +unlock a locked vault. Because of this, passwords or keys cannot be left behind in memory in an |
| 6 | +accessible state. Besides this requirement, some features such as SSH agent need process hardening |
| 7 | +where possible, as required by the protocol specification. |
| 8 | + |
| 9 | +## Zeroizing and process reload |
| 10 | + |
| 11 | +To clear secrets on locking, Bitwarden clients use two techniques, zeroizing and process reload. For |
| 12 | +any memory that lives in Rust, memory is overwritten with zeroes, as soon as it becomes unused or |
| 13 | +gets dropped, which is implemented in |
| 14 | +[lib.rs](https://github.com/bitwarden/sdk-internal/blob/4591981820f12a24e64609fb0a9fd4fdaabbb216/crates/bitwarden-crypto/src/lib.rs#L13). |
| 15 | +This hardens the SDK, and the Rust desktop module (desktop native) against memory being left behind. |
| 16 | +Process reload wipes the entire process - on the web app by reloading the page, on browser |
| 17 | +extensions by reloading the extension, and on desktop by force-crashing the renderer process in the |
| 18 | +[process reload service](https://github.com/bitwarden/clients/blob/16e67566436ae7becbea85f900656c437204824b/libs/common/src/key-management/services/default-process-reload.service.ts#L22). |
| 19 | +The assumption here is that since the process dies, the memory gets wiped too. JavaScript does not |
| 20 | +provide mechanisms for reliably zeroizing memory. Secrets or partial secrets frequently remain in |
| 21 | +memory even after garbage collection cycles complete. |
| 22 | + |
| 23 | +## Process isolation and key protection on desktop apps |
| 24 | + |
| 25 | +Next to process reload and zeroizing, desktop apps can use OS-level protections to harden memory. |
| 26 | +There are two mechanisms used here: Process isolation and key protection. Process isolation uses |
| 27 | +OS-level features to isolate the process from debugger access. Windows and desktop Linux by default |
| 28 | +allow user-space processes to debug other user-space processes and read memory. macOS does not allow |
| 29 | +this by default and requires user consent to allow a process to debug another process. On Linux, |
| 30 | +some distributions such as Ubuntu use |
| 31 | +[yama.ptrace_scope](https://www.kernel.org/doc/Documentation/security/Yama.txt) to limit ptrace |
| 32 | +access. |
| 33 | + |
| 34 | +To harden against user-space memory attacks, Bitwarden desktop isolates the main process. On |
| 35 | +Windows, [`DACL`](https://learn.microsoft.com/en-us/windows/win32/secauthz/dacls-and-aces) is used |
| 36 | +to restrict access to the process, on Linux |
| 37 | +[`PR_SET_DUMPABLE`](https://man7.org/linux/man-pages/man2/pr_set_dumpable.2const.html) is used to |
| 38 | +disable ptrace access and on macOS the process is hardened using the Hardened Runtime entitlements, |
| 39 | +and also by using `PT_DENY_ATTACH` to prevent debugger attachment. On Linux, a dynamic library that |
| 40 | +sets [`PR_SET_DUMPABLE`](https://man7.org/linux/man-pages/man2/pr_set_dumpable.2const.html) is also |
| 41 | +injected into the renderer processes by injecting a shared object into the renderer processes in the |
| 42 | +[process isolation library](https://github.com/bitwarden/clients/blob/16e67566436ae7becbea85f900656c437204824b/apps/desktop/desktop_native/process_isolation/src/lib.rs), |
| 43 | +so that these are isolated too. These mechanisms apply to all apps except for the Snap desktop app. |
| 44 | +Snap does not support |
| 45 | +[`PR_SET_DUMPABLE`](https://man7.org/linux/man-pages/man2/pr_set_dumpable.2const.html) currently and |
| 46 | +breaks file picker support, due to a [bug](https://github.com/flatpak/xdg-desktop-portal/issues/785) |
| 47 | +in the desktop portal. |
| 48 | + |
| 49 | +Next to hardening the entire process, operating systems offer mechanisms to protect cryptographic |
| 50 | +keys in memory. On Windows, |
| 51 | +[`DPAPI`](https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectmemory) can |
| 52 | +be used to encrypt a key in memory, with a key bound to the process. On Linux, |
| 53 | +[`memfd_secret`](https://man7.org/linux/man-pages/man2/memfd_secret.2.html) and |
| 54 | +[`keyctl`](https://man7.org/linux/man-pages/man1/keyctl.1.html) are available, each of which can be |
| 55 | +used to store keys in memory while preventing other processes from reading them. This is used to |
| 56 | +hold the biometric unlock key in memory while the desktop app is locked. Access to this protected |
| 57 | +memory is available via the |
| 58 | +[`EncryptedMemoryStore`](https://github.com/bitwarden/clients/blob/16e67566436ae7becbea85f900656c437204824b/apps/desktop/desktop_native/core/src/secure_memory/encrypted_memory_store.rs#L16) |
| 59 | +abstraction that automatically uses the correct memory protection. |
0 commit comments