diff options
author | ishaanam <ishaana.misra@gmail.com> | 2022-10-26 16:59:34 -0400 |
---|---|---|
committer | ishaanam <ishaana.misra@gmail.com> | 2023-02-14 23:32:40 -0500 |
commit | 493b813e171a389a8b6750b4f2e42e8363a0267e (patch) | |
tree | fdb409524347f808ec2bfae547c2f07345d75cc4 /src | |
parent | 66a86ebabb26a055ca92af846bfa39dbd2f9f722 (diff) |
wallet: ensure that the passphrase is not deleted from memory when being used to rescan
`m_relock_mutex` is introduced so that the passphrase is not
deleted from memory when the timeout provided in
`walletpassphrase` is up, but the wallet is still rescanning.
Diffstat (limited to 'src')
-rw-r--r-- | src/wallet/rpc/backup.cpp | 4 | ||||
-rw-r--r-- | src/wallet/rpc/encrypt.cpp | 14 | ||||
-rw-r--r-- | src/wallet/rpc/transactions.cpp | 1 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 6 | ||||
-rw-r--r-- | src/wallet/wallet.h | 3 |
5 files changed, 18 insertions, 10 deletions
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 94346b31e3..a6940c04d6 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -1655,6 +1655,10 @@ RPCHelpMan importdescriptors() throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait."); } + // Ensure that the wallet is not locked for the remainder of this RPC, as + // the passphrase is used to top up the keypool. + LOCK(pwallet->m_relock_mutex); + const UniValue& requests = main_request.params[0]; const int64_t minimum_timestamp = 1; int64_t now = 0; diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp index 8b818cc4f7..38960bda7b 100644 --- a/src/wallet/rpc/encrypt.cpp +++ b/src/wallet/rpc/encrypt.cpp @@ -90,7 +90,7 @@ RPCHelpMan walletpassphrase() std::weak_ptr<CWallet> weak_wallet = wallet; pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] { if (auto shared_wallet = weak_wallet.lock()) { - LOCK(shared_wallet->cs_wallet); + LOCK2(shared_wallet->m_relock_mutex, shared_wallet->cs_wallet); // Skip if this is not the most recent rpcRunLater callback. if (shared_wallet->nRelockTime != relock_time) return; shared_wallet->Lock(); @@ -122,8 +122,6 @@ RPCHelpMan walletpassphrasechange() std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - LOCK(pwallet->cs_wallet); - if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); } @@ -132,6 +130,8 @@ RPCHelpMan walletpassphrasechange() throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before changing the passphrase."); } + LOCK2(pwallet->m_relock_mutex, pwallet->cs_wallet); + // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) // Alternately, find a way to make request.params[0] mlock()'d to begin with. SecureString strOldWalletPass; @@ -179,8 +179,6 @@ RPCHelpMan walletlock() std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - LOCK(pwallet->cs_wallet); - if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called."); } @@ -189,6 +187,8 @@ RPCHelpMan walletlock() throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before locking the wallet."); } + LOCK2(pwallet->m_relock_mutex, pwallet->cs_wallet); + pwallet->Lock(); pwallet->nRelockTime = 0; @@ -227,8 +227,6 @@ RPCHelpMan encryptwallet() std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - LOCK(pwallet->cs_wallet); - if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt."); } @@ -241,6 +239,8 @@ RPCHelpMan encryptwallet() throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before encrypting the wallet."); } + LOCK2(pwallet->m_relock_mutex, pwallet->cs_wallet); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) // Alternately, find a way to make request.params[0] mlock()'d to begin with. SecureString strWalletPass; diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 0d482b82c6..3bfe296d90 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -880,6 +880,7 @@ RPCHelpMan rescanblockchain() std::optional<int> stop_height; uint256 start_block; + LOCK(pwallet->m_relock_mutex); { LOCK(pwallet->cs_wallet); EnsureWalletIsUnlocked(*pwallet); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b709bd9650..29247ce7c2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -551,7 +551,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, bool fWasLocked = IsLocked(); { - LOCK(cs_wallet); + LOCK2(m_relock_mutex, cs_wallet); Lock(); CCrypter crypter; @@ -786,7 +786,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return false; { - LOCK(cs_wallet); + LOCK2(m_relock_mutex, cs_wallet); mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; WalletBatch* encrypted_batch = new WalletBatch(GetDatabase()); if (!encrypted_batch->TxnBegin()) { @@ -3407,7 +3407,7 @@ bool CWallet::Lock() return false; { - LOCK(cs_wallet); + LOCK2(m_relock_mutex, cs_wallet); if (!vMasterKey.empty()) { memory_cleanse(vMasterKey.data(), vMasterKey.size() * sizeof(decltype(vMasterKey)::value_type)); vMasterKey.clear(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index ed2f8604f7..b164d72503 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -488,6 +488,9 @@ public: // Used to prevent concurrent calls to walletpassphrase RPC. Mutex m_unlock_mutex; + // Used to prevent deleting the passphrase from memory when it is still in use. + RecursiveMutex m_relock_mutex; + bool Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys = false); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); |