Skip to content

Commit 7f985d6

Browse files
committed
Merge #16158: Fix logic of memory_cleanse() on MSVC and clean up docs
f53a70c Improve documentation of memory_cleanse() (Tim Ruffing) cac30a4 Clean up logic in memory_cleanse() for MSVC (Tim Ruffing) Pull request description: When working on bitcoin-core/secp256k1#185, I noticed that the logic in memory_cleanse(), which is supposed to clear memory securely, is weird on MSVC. While it's correct, it's at least a code smell because the code clears the memory twice on MSVC. This weirdness was introduced by #11558. This PR fixes the logic on MSVC and also improves the docs around this function. Best reviewed in individual commits, see the commit messages for more rationale. The second commit touches only comments. ACKs for top commit: practicalswift: utACK f53a70c :-) laanwj: code review ACK f53a70c Tree-SHA512: 1c2fd98ae62b34b3e6e59d1178b293af969a9e06cbb7df02a699ce8802f145a336f72edb178c520e3ecec81f7e8083828f90a5ba6367d966a2c7d7c0dd6c0475
2 parents 7d7b832 + f53a70c commit 7f985d6

File tree

2 files changed

+16
-23
lines changed

2 files changed

+16
-23
lines changed

src/support/cleanse.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,25 @@
1111
#include <Windows.h> // For SecureZeroMemory.
1212
#endif
1313

14-
/* Compilers have a bad habit of removing "superfluous" memset calls that
15-
* are trying to zero memory. For example, when memset()ing a buffer and
16-
* then free()ing it, the compiler might decide that the memset is
17-
* unobservable and thus can be removed.
18-
*
19-
* Previously we used OpenSSL which tried to stop this by a) implementing
20-
* memset in assembly on x86 and b) putting the function in its own file
21-
* for other platforms.
22-
*
23-
* This change removes those tricks in favour of using asm directives to
24-
* scare the compiler away. As best as our compiler folks can tell, this is
25-
* sufficient and will continue to be so.
26-
*
27-
* Adam Langley <[email protected]>
28-
* Commit: ad1907fe73334d6c696c8539646c21b11178f20f
29-
* BoringSSL (LICENSE: ISC)
30-
*/
3114
void memory_cleanse(void *ptr, size_t len)
3215
{
33-
std::memset(ptr, 0, len);
34-
35-
/* As best as we can tell, this is sufficient to break any optimisations that
36-
might try to eliminate "superfluous" memsets. If there's an easy way to
37-
detect memset_s, it would be better to use that. */
3816
#if defined(_MSC_VER)
17+
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
3918
SecureZeroMemory(ptr, len);
4019
#else
20+
std::memset(ptr, 0, len);
21+
22+
/* Memory barrier that scares the compiler away from optimizing out the memset.
23+
*
24+
* Quoting Adam Langley <[email protected]> in commit ad1907fe73334d6c696c8539646c21b11178f20f
25+
* in BoringSSL (ISC License):
26+
* As best as we can tell, this is sufficient to break any optimisations that
27+
* might try to eliminate "superfluous" memsets.
28+
* This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
29+
* is pretty efficient because the compiler can still implement the memset() efficiently,
30+
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
31+
* Yang et al. (USENIX Security 2017) for more background.
32+
*/
4133
__asm__ __volatile__("" : : "r"(ptr) : "memory");
4234
#endif
4335
}

src/support/cleanse.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
#include <stdlib.h>
1010

11-
// Attempt to overwrite data in the specified memory span.
11+
/** Secure overwrite a buffer (possibly containing secret data) with zero-bytes. The write
12+
* operation will not be optimized out by the compiler. */
1213
void memory_cleanse(void *ptr, size_t len);
1314

1415
#endif // BITCOIN_SUPPORT_CLEANSE_H

0 commit comments

Comments
 (0)