mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 20:42:59 +01:00
Merge #18814: rpc: Relock wallet only if most recent callback
9f59dde9740d065118bdddde75ef9f4e4603a7b1 rpc: Relock wallet only if most recent callback (João Barbosa) a2e6db5c4f1bb52a8814102b628e51652493d06a rpc: Add mutex to guard deadlineTimers (João Barbosa) Pull request description: This PR fixes an early relocking race condition from #18811 where old relock callback runs after new wallet unlock code and nRelockTime update but before rpcRunLater call, causing early relock and incorrect nRelockTime time Issue introduced in #18487. Fixes #18811. ACKs for top commit: MarcoFalke: ACK 9f59dde9740d065118bdddde75ef9f4e4603a7b1 ryanofsky: Code review ACK 9f59dde9740d065118bdddde75ef9f4e4603a7b1. No changes since last review except squashing commits. jonatack: ACK 9f59dde9740d065118bdddde75ef Tree-SHA512: 2f7fc03e5ab6037337f2d82dfad432495cc337c77d07c968ee2355105db6292f24543c03456f5402e0e759577a4327758f9372f7ea29de6d56dc3695fda9b379
This commit is contained in:
parent
e1630d8fc3
commit
da7ca00f03
@ -28,7 +28,8 @@ static std::string rpcWarmupStatus GUARDED_BY(g_rpc_warmup_mutex) = "RPC server
|
|||||||
/* Timer-creating functions */
|
/* Timer-creating functions */
|
||||||
static RPCTimerInterface* timerInterface = nullptr;
|
static RPCTimerInterface* timerInterface = nullptr;
|
||||||
/* Map of name to timer. */
|
/* Map of name to timer. */
|
||||||
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
|
static Mutex g_deadline_timers_mutex;
|
||||||
|
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers GUARDED_BY(g_deadline_timers_mutex);
|
||||||
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler, std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions);
|
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler, std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions);
|
||||||
|
|
||||||
// Any commands submitted by this user will have their commands filtered based on the mapPlatformRestrictions
|
// Any commands submitted by this user will have their commands filtered based on the mapPlatformRestrictions
|
||||||
@ -330,7 +331,7 @@ void InterruptRPC()
|
|||||||
void StopRPC()
|
void StopRPC()
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::RPC, "Stopping RPC\n");
|
LogPrint(BCLog::RPC, "Stopping RPC\n");
|
||||||
deadlineTimers.clear();
|
WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
|
||||||
DeleteAuthCookie();
|
DeleteAuthCookie();
|
||||||
g_rpcSignals.Stopped();
|
g_rpcSignals.Stopped();
|
||||||
}
|
}
|
||||||
@ -609,6 +610,7 @@ void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nS
|
|||||||
{
|
{
|
||||||
if (!timerInterface)
|
if (!timerInterface)
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
|
||||||
|
LOCK(g_deadline_timers_mutex);
|
||||||
deadlineTimers.erase(name);
|
deadlineTimers.erase(name);
|
||||||
LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
|
LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
|
||||||
deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
|
deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
|
||||||
|
@ -1927,6 +1927,9 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
|
|||||||
CWallet* const pwallet = wallet.get();
|
CWallet* const pwallet = wallet.get();
|
||||||
|
|
||||||
int64_t nSleepTime;
|
int64_t nSleepTime;
|
||||||
|
int64_t relock_time;
|
||||||
|
// Prevent concurrent calls to walletpassphrase with the same wallet.
|
||||||
|
LOCK(pwallet->m_unlock_mutex);
|
||||||
{
|
{
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
|
|
||||||
@ -1975,7 +1978,7 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
|
|||||||
pwallet->TopUpKeyPool();
|
pwallet->TopUpKeyPool();
|
||||||
|
|
||||||
pwallet->nRelockTime = GetTime() + nSleepTime;
|
pwallet->nRelockTime = GetTime() + nSleepTime;
|
||||||
|
relock_time = pwallet->nRelockTime;
|
||||||
}
|
}
|
||||||
// rpcRunLater must be called without cs_wallet held otherwise a deadlock
|
// rpcRunLater must be called without cs_wallet held otherwise a deadlock
|
||||||
// can occur. The deadlock would happen when RPCRunLater removes the
|
// can occur. The deadlock would happen when RPCRunLater removes the
|
||||||
@ -1986,9 +1989,11 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
|
|||||||
// wallet before the following callback is called. If a valid shared pointer
|
// wallet before the following callback is called. If a valid shared pointer
|
||||||
// is acquired in the callback then the wallet is still loaded.
|
// is acquired in the callback then the wallet is still loaded.
|
||||||
std::weak_ptr<CWallet> weak_wallet = wallet;
|
std::weak_ptr<CWallet> weak_wallet = wallet;
|
||||||
pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet] {
|
pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
|
||||||
if (auto shared_wallet = weak_wallet.lock()) {
|
if (auto shared_wallet = weak_wallet.lock()) {
|
||||||
LOCK(shared_wallet->cs_wallet);
|
LOCK(shared_wallet->cs_wallet);
|
||||||
|
// Skip if this is not the most recent rpcRunLater callback.
|
||||||
|
if (shared_wallet->nRelockTime != relock_time) return;
|
||||||
shared_wallet->Lock();
|
shared_wallet->Lock();
|
||||||
shared_wallet->nRelockTime = 0;
|
shared_wallet->nRelockTime = 0;
|
||||||
}
|
}
|
||||||
|
@ -965,8 +965,10 @@ public:
|
|||||||
std::vector<std::string> GetDestValues(const std::string& prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
std::vector<std::string> GetDestValues(const std::string& prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
|
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
|
||||||
int64_t nRelockTime = 0;
|
int64_t nRelockTime GUARDED_BY(cs_wallet){0};
|
||||||
|
|
||||||
|
// Used to prevent concurrent calls to walletpassphrase RPC.
|
||||||
|
Mutex m_unlock_mutex;
|
||||||
bool Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnly = false, bool accept_no_keys = false);
|
bool Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnly = false, bool accept_no_keys = false);
|
||||||
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
|
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
|
||||||
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
||||||
|
Loading…
Reference in New Issue
Block a user