Skip to content

Commit 9911e82

Browse files
authored
Add memory hardening deep-dive (#749)
* Add section about memory hardening * Format * Fix grammar and spelling * Clean up * Move to deep-dives * Apply feedback * Add links * Fix citation rendering * Change references to names * Rename MacOS to macOS * Rename MacOS to macOS
1 parent 22bedb0 commit 9911e82

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

custom-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Yellowpages
9797
Yubico
9898
YubiKey
9999
YubiKeys
100+
Zeroizing
100101

101102
# Forbidden words
102103
!auto-fill
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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

Comments
 (0)