Skip to content

Commit

Permalink
Merge bitcoin#16158: Fix logic of memory_cleanse() on MSVC and clean …
Browse files Browse the repository at this point in the history
…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 bitcoin#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
  • Loading branch information
laanwj authored and PastaPastaPasta committed Jun 28, 2021
1 parent 449b891 commit f95eee6
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 23 deletions.
36 changes: 14 additions & 22 deletions src/support/cleanse.cpp
Expand Up @@ -11,33 +11,25 @@
#include <Windows.h> // For SecureZeroMemory.
#endif

/* Compilers have a bad habit of removing "superfluous" memset calls that
* are trying to zero memory. For example, when memset()ing a buffer and
* then free()ing it, the compiler might decide that the memset is
* unobservable and thus can be removed.
*
* Previously we used OpenSSL which tried to stop this by a) implementing
* memset in assembly on x86 and b) putting the function in its own file
* for other platforms.
*
* This change removes those tricks in favour of using asm directives to
* scare the compiler away. As best as our compiler folks can tell, this is
* sufficient and will continue to be so.
*
* Adam Langley <agl@google.com>
* Commit: ad1907fe73334d6c696c8539646c21b11178f20f
* BoringSSL (LICENSE: ISC)
*/
void memory_cleanse(void *ptr, size_t len)
{
std::memset(ptr, 0, len);

/* As best as we can tell, this is sufficient to break any optimisations that
might try to eliminate "superfluous" memsets. If there's an easy way to
detect memset_s, it would be better to use that. */
#if defined(_MSC_VER)
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
#else
std::memset(ptr, 0, len);

/* Memory barrier that scares the compiler away from optimizing out the memset.
*
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
* in BoringSSL (ISC License):
* As best as we can tell, this is sufficient to break any optimisations that
* might try to eliminate "superfluous" memsets.
* This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
* is pretty efficient because the compiler can still implement the memset() efficiently,
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
* Yang et al. (USENIX Security 2017) for more background.
*/
__asm__ __volatile__("" : : "r"(ptr) : "memory");
#endif
}
3 changes: 2 additions & 1 deletion src/support/cleanse.h
Expand Up @@ -8,7 +8,8 @@

#include <stdlib.h>

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

#endif // BITCOIN_SUPPORT_CLEANSE_H

0 comments on commit f95eee6

Please sign in to comment.