mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge bitcoin/bitcoin#28774: wallet: avoid returning a reference to vMasterKey after releasing the mutex that guards it
32a9f13cb805ecf6aebb5cf4e5d92b8a47c4548b wallet: avoid returning a reference to vMasterKey after releasing the mutex that guards it (Vasil Dimov)
Pull request description:
`CWallet::GetEncryptionKey()` would return a reference to the internal
`CWallet::vMasterKey`, guarded by `CWallet::cs_wallet`, which is unsafe.
Returning a copy would be a shorter solution, but could have security
implications of the master key remaining somewhere in the memory even
after `CWallet::Lock()` (the current calls to
`CWallet::GetEncryptionKey()` are safe, but that is not future proof).
So, instead of `EncryptSecret(m_storage.GetEncryptionKey(), ...)`
change the `GetEncryptionKey()` method to provide the encryption
key to a given callback:
`m_storage.WithEncryptionKey([](const CKeyingMaterial& k) { EncryptSecret(k, ...); })`
This silences the following (clang 18):
```
wallet/wallet.cpp:3520:12: error: returning variable 'vMasterKey' by reference requires holding mutex 'cs_wallet' [-Werror,-Wthread-safety-reference-return]
3520 | return vMasterKey;
| ^
```
---
_Previously this PR modified both ArgsManager and wallet code. But the ArgsManager commit 856c88776f
was merged in https://github.com/bitcoin/bitcoin/pull/29040 so now this only affects wallet code. The previous PR description was:_
Avoid this unsafe pattern from `ArgsManager` and `CWallet`:
```cpp
class A
{
Mutex mutex;
Foo member GUARDED_BY(mutex);
const Foo& Get()
{
LOCK(mutex);
return member;
} // callers of `Get()` will have access to `member` without owning the mutex.
```
ACKs for top commit:
achow101:
ACK 32a9f13cb805ecf6aebb5cf4e5d92b8a47c4548b
ryanofsky:
Code review ACK 32a9f13cb805ecf6aebb5cf4e5d92b8a47c4548b. This seems like a potentially real race condition, and the fix here is pretty simple.
furszy:
ACK 32a9f13c
Tree-SHA512: 133da84691642afc1a73cf14ad004a7266cb4be1a6a3ec634d131dca5dbcdef52522c1d5eb04f5b6c4e06e1fc3e6ac57315f8fe1e207b464ca025c2b4edefdc1
This commit is contained in:
parent
6d452845dc
commit
898282d620
@ -342,8 +342,11 @@ void LegacyScriptPubKeyMan::UpgradeKeyMetadata()
|
||||
CHDChain hdChainCurrent;
|
||||
if (!GetHDChain(hdChainCurrent))
|
||||
throw std::runtime_error(std::string(__func__) + ": GetHDChain failed");
|
||||
if (!DecryptHDChain(m_storage.GetEncryptionKey(), hdChainCurrent))
|
||||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return DecryptHDChain(encryption_key, hdChainCurrent);
|
||||
})) {
|
||||
throw std::runtime_error(std::string(__func__) + ": DecryptHDChain failed");
|
||||
}
|
||||
|
||||
CExtKey masterKey;
|
||||
SecureVector vchSeed = hdChainCurrent.GetSeed();
|
||||
@ -474,8 +477,11 @@ bool LegacyScriptPubKeyMan::GetDecryptedHDChain(CHDChain& hdChainRet)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DecryptHDChain(m_storage.GetEncryptionKey(), hdChainTmp))
|
||||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return DecryptHDChain(encryption_key, hdChainTmp);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure seed matches this chain
|
||||
if (hdChainTmp.GetID() != hdChainTmp.GetSeedHash())
|
||||
@ -911,7 +917,9 @@ bool LegacyScriptPubKeyMan::AddKeyPubKeyInner(const CKey& key, const CPubKey &pu
|
||||
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
CKeyingMaterial vchSecret(key.begin(), key.end());
|
||||
if (!EncryptSecret(m_storage.GetEncryptionKey(), vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
|
||||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return EncryptSecret(encryption_key, vchSecret, pubkey.GetHash(), vchCryptedSecret);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -933,7 +941,9 @@ bool LegacyScriptPubKeyMan::GetKeyInner(const CKeyID &address, CKey& keyOut) con
|
||||
{
|
||||
const CPubKey &vchPubKey = (*mi).second.first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
||||
return DecryptKey(m_storage.GetEncryptionKey(), vchCryptedSecret, vchPubKey, keyOut);
|
||||
return m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return DecryptKey(encryption_key, vchCryptedSecret, vchPubKey, keyOut);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1164,8 +1174,11 @@ bool LegacyScriptPubKeyMan::GetKey(const CKeyID &address, CKey& keyOut) const
|
||||
CHDChain hdChainCurrent;
|
||||
if (!GetHDChain(hdChainCurrent))
|
||||
throw std::runtime_error(std::string(__func__) + ": GetHDChain failed");
|
||||
if (!DecryptHDChain(m_storage.GetEncryptionKey(), hdChainCurrent))
|
||||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return DecryptHDChain(encryption_key, hdChainCurrent);
|
||||
})) {
|
||||
throw std::runtime_error(std::string(__func__) + ": DecryptHDChain failed");
|
||||
}
|
||||
// make sure seed matches this chain
|
||||
if (hdChainCurrent.GetID() != hdChainCurrent.GetSeedHash())
|
||||
throw std::runtime_error(std::string(__func__) + ": Wrong HD chain!");
|
||||
@ -1276,8 +1289,11 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
|
||||
throw std::runtime_error(std::string(__func__) + ": GetHDChain failed");
|
||||
}
|
||||
|
||||
if (!DecryptHDChain(m_storage.GetEncryptionKey(), hdChainTmp))
|
||||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return DecryptHDChain(encryption_key, hdChainTmp);
|
||||
})) {
|
||||
throw std::runtime_error(std::string(__func__) + ": DecryptHDChain failed");
|
||||
}
|
||||
// make sure seed matches this chain
|
||||
if (hdChainTmp.GetID() != hdChainTmp.GetSeedHash())
|
||||
throw std::runtime_error(std::string(__func__) + ": Wrong HD chain!");
|
||||
@ -1897,7 +1913,9 @@ std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const
|
||||
const CPubKey& pubkey = key_pair.second.first;
|
||||
const std::vector<unsigned char>& crypted_secret = key_pair.second.second;
|
||||
CKey key;
|
||||
DecryptKey(m_storage.GetEncryptionKey(), crypted_secret, pubkey, key);
|
||||
m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return DecryptKey(encryption_key, crypted_secret, pubkey, key);
|
||||
});
|
||||
keys[pubkey.GetID()] = key;
|
||||
}
|
||||
return keys;
|
||||
@ -2010,7 +2028,9 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
|
||||
|
||||
std::vector<unsigned char> crypted_secret;
|
||||
CKeyingMaterial secret(key.begin(), key.end());
|
||||
if (!EncryptSecret(m_storage.GetEncryptionKey(), secret, pubkey.GetHash(), crypted_secret)) {
|
||||
if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
|
||||
return EncryptSecret(encryption_key, secret, pubkey.GetHash(), crypted_secret);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
|
||||
@ -38,7 +39,8 @@ public:
|
||||
virtual void UnsetBlankWalletFlag(WalletBatch&) = 0;
|
||||
virtual bool CanSupportFeature(enum WalletFeature) const = 0;
|
||||
virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr) = 0;
|
||||
virtual const CKeyingMaterial& GetEncryptionKey() const = 0;
|
||||
//! Pass the encryption key to cb().
|
||||
virtual bool WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const = 0;
|
||||
virtual bool HasEncryptionKeys() const = 0;
|
||||
virtual bool IsLocked(bool fForMixing) const = 0;
|
||||
|
||||
|
@ -5743,9 +5743,10 @@ void CWallet::SetupLegacyScriptPubKeyMan()
|
||||
m_spk_managers[spk_manager->GetID()] = std::move(spk_manager);
|
||||
}
|
||||
|
||||
const CKeyingMaterial& CWallet::GetEncryptionKey() const
|
||||
bool CWallet::WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const
|
||||
{
|
||||
return vMasterKey;
|
||||
LOCK(cs_wallet);
|
||||
return cb(vMasterKey);
|
||||
}
|
||||
|
||||
bool CWallet::HasEncryptionKeys() const
|
||||
|
@ -1468,7 +1468,8 @@ public:
|
||||
//! Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
|
||||
void SetupLegacyScriptPubKeyMan();
|
||||
|
||||
const CKeyingMaterial& GetEncryptionKey() const override;
|
||||
bool WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const override;
|
||||
|
||||
bool HasEncryptionKeys() const override;
|
||||
|
||||
/** Get last block processed height */
|
||||
|
Loading…
Reference in New Issue
Block a user