Merge #9937: rpc: Prevent dumpwallet from overwriting files

0cd9273 rpc: Prevent `dumpwallet` from overwriting files (Wladimir J. van der Laan)

Pull request description:

  Prevent arbitrary files from being overwritten by `dumpwallet`. There have been reports that users have overwritten wallet files this way. It may also avoid other security issues.

  Fixes #9934. Adds mention to release notes and adds a test.

Tree-SHA512: 268c98636d40924d793b55a685a0b419bafd834ad369edaec08227ebe26ed4470ddea73008d1c4beb10ea445db1b0bb8e3546ba8fc2d1a411ebd4a0de8ce9120
This commit is contained in:
Wladimir J. van der Laan 2017-10-04 15:00:59 +02:00
commit 7f11ef2608
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
3 changed files with 19 additions and 3 deletions

View file

@ -83,6 +83,9 @@ Low-level RPC changes
* `getwalletinfo` * `getwalletinfo`
* `getmininginfo` * `getmininginfo`
- `dumpwallet` no longer allows overwriting files. This is a security measure
as well as prevents dangerous user mistakes.
Credits Credits
======= =======

View file

@ -600,7 +600,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1) if (request.fHelp || request.params.size() != 1)
throw std::runtime_error( throw std::runtime_error(
"dumpwallet \"filename\"\n" "dumpwallet \"filename\"\n"
"\nDumps all wallet keys in a human-readable format.\n" "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n" "1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n"
"\nResult:\n" "\nResult:\n"
@ -616,9 +616,19 @@ UniValue dumpwallet(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet); EnsureWalletIsUnlocked(pwallet);
std::ofstream file;
boost::filesystem::path filepath = request.params[0].get_str(); boost::filesystem::path filepath = request.params[0].get_str();
filepath = boost::filesystem::absolute(filepath); filepath = boost::filesystem::absolute(filepath);
/* Prevent arbitrary files from being overwritten. There have been reports
* that users have overwritten wallet files this way:
* https://github.com/bitcoin/bitcoin/issues/9934
* It may also avoid other security issues.
*/
if (boost::filesystem::exists(filepath)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
}
std::ofstream file;
file.open(filepath.string().c_str()); file.open(filepath.string().c_str());
if (!file.is_open()) if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");

View file

@ -7,7 +7,7 @@
import os import os
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal from test_framework.util import (assert_equal, assert_raises_jsonrpc)
def read_dump(file_name, addrs, hd_master_addr_old): def read_dump(file_name, addrs, hd_master_addr_old):
@ -105,5 +105,8 @@ class WalletDumpTest(BitcoinTestFramework):
assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now
assert_equal(found_addr_rsv, 90*2) assert_equal(found_addr_rsv, 90*2)
# Overwriting should fail
assert_raises_jsonrpc(-8, "already exists", self.nodes[0].dumpwallet, tmpdir + "/node0/wallet.unencrypted.dump")
if __name__ == '__main__': if __name__ == '__main__':
WalletDumpTest().main () WalletDumpTest().main ()