Auto merge of #4482 - str4d:memory_cleanse-backports, r=str4d
memory_cleanse backports Cherry-picked from the following upstream PRs: - bitcoin/bitcoin#10308 - bitcoin/bitcoin#11196 - bitcoin/bitcoin#11558 - Only the changes that did not conflict. - bitcoin/bitcoin#16158 Part of #145.
This commit is contained in:
commit
7a0fe273d8
|
@ -22,7 +22,7 @@ static void Base58Encode(benchmark::State& state)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
while (state.KeepRunning()) {
|
while (state.KeepRunning()) {
|
||||||
EncodeBase58(buff.begin(), buff.end());
|
EncodeBase58(buff.data(), buff.data() + buff.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ static const int MIN_CORES = 2;
|
||||||
static const size_t BATCHES = 101;
|
static const size_t BATCHES = 101;
|
||||||
static const size_t BATCH_SIZE = 30;
|
static const size_t BATCH_SIZE = 30;
|
||||||
static const int PREVECTOR_SIZE = 28;
|
static const int PREVECTOR_SIZE = 28;
|
||||||
static const int QUEUE_BATCH_SIZE = 128;
|
static const unsigned int QUEUE_BATCH_SIZE = 128;
|
||||||
static void CCheckQueueSpeed(benchmark::State& state)
|
static void CCheckQueueSpeed(benchmark::State& state)
|
||||||
{
|
{
|
||||||
struct FakeJobNoWork {
|
struct FakeJobNoWork {
|
||||||
|
|
10
src/compat.h
10
src/compat.h
|
@ -31,6 +31,7 @@
|
||||||
#include <mswsock.h>
|
#include <mswsock.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#include <stdint.h>
|
||||||
#else
|
#else
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
@ -72,6 +73,15 @@ typedef u_int SOCKET;
|
||||||
#else
|
#else
|
||||||
#define MAX_PATH 1024
|
#define MAX_PATH 1024
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if !defined(ssize_t)
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef int64_t ssize_t;
|
||||||
|
#else
|
||||||
|
typedef int32_t ssize_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
|
// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
|
||||||
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
|
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
|
||||||
|
|
|
@ -5,9 +5,34 @@
|
||||||
|
|
||||||
#include "cleanse.h"
|
#include "cleanse.h"
|
||||||
|
|
||||||
#include <openssl/crypto.h>
|
#include <cstring>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <Windows.h> // For SecureZeroMemory.
|
||||||
|
#endif
|
||||||
|
|
||||||
void memory_cleanse(void *ptr, size_t len)
|
void memory_cleanse(void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
OPENSSL_cleanse(ptr, len);
|
#if defined(_MSC_VER)
|
||||||
|
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||||
|
SecureZeroMemory(ptr, len);
|
||||||
|
#else
|
||||||
|
std::memset(ptr, 0, len);
|
||||||
|
|
||||||
|
/* In order to prevent the compiler from optimizing out the memset, this uses an
|
||||||
|
* unremovable (see https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile )
|
||||||
|
* asm block that the compiler must assume could access arbitary memory, including
|
||||||
|
* the zero bytes written by std::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 by memzero_explicit() in 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/** 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);
|
void memory_cleanse(void *ptr, size_t len);
|
||||||
|
|
||||||
#endif // BITCOIN_SUPPORT_CLEANSE_H
|
#endif // BITCOIN_SUPPORT_CLEANSE_H
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <boost/scope_exit.hpp>
|
||||||
|
|
||||||
#include <db_cxx.h>
|
#include <db_cxx.h>
|
||||||
|
|
||||||
|
@ -128,21 +129,22 @@ protected:
|
||||||
Dbt datValue;
|
Dbt datValue;
|
||||||
datValue.set_flags(DB_DBT_MALLOC);
|
datValue.set_flags(DB_DBT_MALLOC);
|
||||||
int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
|
int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
|
||||||
memset(datKey.get_data(), 0, datKey.get_size());
|
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||||
if (datValue.get_data() == NULL)
|
if (datValue.get_data() != NULL) {
|
||||||
return false;
|
BOOST_SCOPE_EXIT_TPL(&datValue) {
|
||||||
|
// Clear and free memory
|
||||||
|
memory_cleanse(datValue.get_data(), datValue.get_size());
|
||||||
|
free(datValue.get_data());
|
||||||
|
} BOOST_SCOPE_EXIT_END
|
||||||
|
|
||||||
// Unserialize value
|
// Unserialize value
|
||||||
try {
|
try {
|
||||||
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
||||||
ssValue >> value;
|
ssValue >> value;
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear and free memory
|
|
||||||
memset(datValue.get_data(), 0, datValue.get_size());
|
|
||||||
free(datValue.get_data());
|
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +172,8 @@ protected:
|
||||||
int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
|
int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
|
||||||
|
|
||||||
// Clear memory in case it was a private key
|
// Clear memory in case it was a private key
|
||||||
memset(datKey.get_data(), 0, datKey.get_size());
|
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||||
memset(datValue.get_data(), 0, datValue.get_size());
|
memory_cleanse(datValue.get_data(), datValue.get_size());
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +195,7 @@ protected:
|
||||||
int ret = pdb->del(activeTxn, &datKey, 0);
|
int ret = pdb->del(activeTxn, &datKey, 0);
|
||||||
|
|
||||||
// Clear memory
|
// Clear memory
|
||||||
memset(datKey.get_data(), 0, datKey.get_size());
|
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||||
return (ret == 0 || ret == DB_NOTFOUND);
|
return (ret == 0 || ret == DB_NOTFOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +215,7 @@ protected:
|
||||||
int ret = pdb->exists(activeTxn, &datKey, 0);
|
int ret = pdb->exists(activeTxn, &datKey, 0);
|
||||||
|
|
||||||
// Clear memory
|
// Clear memory
|
||||||
memset(datKey.get_data(), 0, datKey.get_size());
|
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,8 +260,8 @@ protected:
|
||||||
ssValue.write((char*)datValue.get_data(), datValue.get_size());
|
ssValue.write((char*)datValue.get_data(), datValue.get_size());
|
||||||
|
|
||||||
// Clear and free memory
|
// Clear and free memory
|
||||||
memset(datKey.get_data(), 0, datKey.get_size());
|
memory_cleanse(datKey.get_data(), datKey.get_size());
|
||||||
memset(datValue.get_data(), 0, datValue.get_size());
|
memory_cleanse(datValue.get_data(), datValue.get_size());
|
||||||
free(datKey.get_data());
|
free(datKey.get_data());
|
||||||
free(datValue.get_data());
|
free(datValue.get_data());
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue