Merge #12905: [rpcwallet] Clamp walletpassphrase value at 100M seconds

2b2b96cd45 Use std::bind instead of boost::bind to re-lock the wallet (Suhas Daftuar)
662d19ff72 [rpcwallet] Clamp walletpassphrase value at 100M seconds (Suhas Daftuar)

Pull request description:

  Larger values seem to trigger a bug on macos+libevent (resulting in the rpc server stopping).

Tree-SHA512: 890f3b641f6c586e2f8f629a9d23bca6ceb8b237b285561aad488cb7adf941a21177d3129d0c2b8293c0a673cd8e401957dbe2b6b3b7c8c4e991bb411d260102
This commit is contained in:
MarcoFalke 2018-04-08 12:58:42 -04:00
commit bd42b85e8b
No known key found for this signature in database
GPG Key ID: D2EA4850E7528B25
2 changed files with 13 additions and 10 deletions

View File

@ -37,6 +37,8 @@
#include <univalue.h> #include <univalue.h>
#include <functional>
static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request) CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
@ -2349,8 +2351,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n" "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"passphrase\" (string, required) The wallet passphrase\n" "1. \"passphrase\" (string, required) The wallet passphrase\n"
"2. timeout (numeric, required) The time to keep the decryption key in seconds. Limited to at most 1073741824 (2^30) seconds.\n" "2. timeout (numeric, required) The time to keep the decryption key in seconds; capped at 100000000 (~3 years).\n"
" Any value greater than 1073741824 seconds will be set to 1073741824 seconds.\n"
"\nNote:\n" "\nNote:\n"
"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n" "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
"time that overrides the old one.\n" "time that overrides the old one.\n"
@ -2383,9 +2384,10 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
if (nSleepTime < 0) { if (nSleepTime < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
} }
// Clamp timeout to 2^30 seconds // Clamp timeout
if (nSleepTime > (int64_t)1 << 30) { constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
nSleepTime = (int64_t)1 << 30; if (nSleepTime > MAX_SLEEP_TIME) {
nSleepTime = MAX_SLEEP_TIME;
} }
if (strWalletPass.length() > 0) if (strWalletPass.length() > 0)
@ -2402,7 +2404,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
pwallet->TopUpKeyPool(); pwallet->TopUpKeyPool();
pwallet->nRelockTime = GetTime() + nSleepTime; pwallet->nRelockTime = GetTime() + nSleepTime;
RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), boost::bind(LockWallet, pwallet), nSleepTime); RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), std::bind(LockWallet, pwallet), nSleepTime);
return NullUniValue; return NullUniValue;
} }

View File

@ -64,14 +64,15 @@ class WalletEncryptionTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10) assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10)
# Check the timeout # Check the timeout
# Check a time less than the limit # Check a time less than the limit
expected_time = int(time.time()) + (1 << 30) - 600 MAX_VALUE = 100000000
self.nodes[0].walletpassphrase(passphrase2, (1 << 30) - 600) expected_time = int(time.time()) + MAX_VALUE - 600
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)
actual_time = self.nodes[0].getwalletinfo()['unlocked_until'] actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time) assert_greater_than_or_equal(actual_time, expected_time)
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
# Check a time greater than the limit # Check a time greater than the limit
expected_time = int(time.time()) + (1 << 30) - 1 expected_time = int(time.time()) + MAX_VALUE - 1
self.nodes[0].walletpassphrase(passphrase2, (1 << 33)) self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)
actual_time = self.nodes[0].getwalletinfo()['unlocked_until'] actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time) assert_greater_than_or_equal(actual_time, expected_time)
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer assert_greater_than(expected_time + 5, actual_time) # 5 second buffer