aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2018-07-06 15:54:03 +0200
committerDaniel Kraft <d@domob.eu>2018-07-07 14:25:09 +0200
commit57889e688dd0987a1e087cd48d216a413127601e (patch)
treefcdc718f8cb7f89da4ae4f58895f8b8bd0f6ad7d
parent0212187fc624ea4a02fc99bc57ebd413499a9ee1 (diff)
downloadbitcoin-57889e688dd0987a1e087cd48d216a413127601e.tar.xz
bitcoin-tx: Stricter check for valid integers
Just calling atoi to convert strings to integers does not check for valid integers very thoroughly; in particular, it just ignores everything starting from the first non-numeral character. Even a string like "foo" is fine and silently returns 0. This meant that bitcoin-tx would not fail if such a string was passed in various places where an integer is expected (like the locktime or an input/output index); this means that it would, for instance, silently accept a typo and interpret it in an unexpected way. In this change, we use ParseInt64 for parsing strings to integers, which actually verifies that the full string is valid as number. New tests in the bitcoin-util-test cover the new error paths.
-rw-r--r--src/bitcoin-tx.cpp42
-rw-r--r--test/util/data/bitcoin-util-test.json55
2 files changed, 75 insertions, 22 deletions
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index ab0efde05c..181e2bb1bc 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -193,18 +193,18 @@ static CAmount ExtractAndValidateValue(const std::string& strValue)
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
{
- int64_t newVersion = atoi64(cmdVal);
- if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
- throw std::runtime_error("Invalid TX version requested");
+ int64_t newVersion;
+ if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
+ throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
tx.nVersion = (int) newVersion;
}
static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
{
- int64_t newLocktime = atoi64(cmdVal);
- if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
- throw std::runtime_error("Invalid TX locktime requested");
+ int64_t newLocktime;
+ if (!ParseInt64(cmdVal, &newLocktime) || newLocktime < 0LL || newLocktime > 0xffffffffLL)
+ throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");
tx.nLockTime = (unsigned int) newLocktime;
}
@@ -212,8 +212,8 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested index
- int inIdx = atoi(strInIdx);
- if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
+ int64_t inIdx;
+ if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}
@@ -248,10 +248,10 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
// extract and validate vout
- std::string strVout = vStrInputParts[1];
- int vout = atoi(strVout);
- if ((vout < 0) || (vout > (int)maxVout))
- throw std::runtime_error("invalid TX input vout");
+ const std::string& strVout = vStrInputParts[1];
+ int64_t vout;
+ if (!ParseInt64(strVout, &vout) || vout < 0 || vout > static_cast<int64_t>(maxVout))
+ throw std::runtime_error("invalid TX input vout '" + strVout + "'");
// extract the optional sequence number
uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
@@ -481,10 +481,9 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested deletion index
- int inIdx = atoi(strInIdx);
- if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
- std::string strErr = "Invalid TX input index '" + strInIdx + "'";
- throw std::runtime_error(strErr.c_str());
+ int64_t inIdx;
+ if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
+ throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}
// delete input from transaction
@@ -494,10 +493,9 @@ static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInId
static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
{
// parse requested deletion index
- int outIdx = atoi(strOutIdx);
- if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
- std::string strErr = "Invalid TX output index '" + strOutIdx + "'";
- throw std::runtime_error(strErr.c_str());
+ int64_t outIdx;
+ if (!ParseInt64(strOutIdx, &outIdx) || outIdx < 0 || outIdx >= static_cast<int64_t>(tx.vout.size())) {
+ throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
}
// delete output from transaction
@@ -593,7 +591,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
uint256 txid = ParseHashStr(prevOut["txid"].get_str(), "txid");
- int nOut = atoi(prevOut["vout"].getValStr());
+ const int nOut = prevOut["vout"].get_int();
if (nOut < 0)
throw std::runtime_error("vout must be positive");
diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json
index a115aa30d9..f2213f4f2e 100644
--- a/test/util/data/bitcoin-util-test.json
+++ b/test/util/data/bitcoin-util-test.json
@@ -27,6 +27,12 @@
"description": "Creates a blank transaction when nothing is piped into bitcoin-tx (output in json)"
},
{ "exec": "./bitcoin-tx",
+ "args": ["-create", "nversion=1foo"],
+ "return_code": 1,
+ "error_txt": "error: Invalid TX version requested",
+ "description": "Tests the check for invalid nversion value"
+ },
+ { "exec": "./bitcoin-tx",
"args": ["-", "delin=1"],
"input": "tx394b54bb.hex",
"output_cmp": "tt-delin1-out.hex",
@@ -46,6 +52,13 @@
"description": "Attempts to delete an input with a bad index from a transaction. Expected to fail."
},
{ "exec": "./bitcoin-tx",
+ "args": ["-", "delin=1foo"],
+ "input": "tx394b54bb.hex",
+ "return_code": 1,
+ "error_txt": "error: Invalid TX input index",
+ "description": "Tests the check for an invalid input index with delin"
+ },
+ { "exec": "./bitcoin-tx",
"args": ["-", "delout=1"],
"input": "tx394b54bb.hex",
"output_cmp": "tt-delout1-out.hex",
@@ -65,6 +78,13 @@
"description": "Attempts to delete an output with a bad index from a transaction. Expected to fail."
},
{ "exec": "./bitcoin-tx",
+ "args": ["-", "delout=1foo"],
+ "input": "tx394b54bb.hex",
+ "return_code": 1,
+ "error_txt": "error: Invalid TX output index",
+ "description": "Tests the check for an invalid output index with delout"
+ },
+ { "exec": "./bitcoin-tx",
"args": ["-", "locktime=317000"],
"input": "tx394b54bb.hex",
"output_cmp": "tt-locktime317000-out.hex",
@@ -77,6 +97,29 @@
"description": "Adds an nlocktime to a transaction (output in json)"
},
{ "exec": "./bitcoin-tx",
+ "args": ["-create", "locktime=317000foo"],
+ "return_code": 1,
+ "error_txt": "error: Invalid TX locktime requested",
+ "description": "Tests the check for invalid locktime value"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "replaceable=0foo"],
+ "return_code": 1,
+ "error_txt": "error: Invalid TX input index",
+ "description": "Tests the check for an invalid input index with replaceable"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0x"],
+ "return_code": 1,
+ "error_txt": "error: invalid TX input vout",
+ "description": "Tests the check for an invalid vout value when adding an input"
+ },
+ { "exec": "./bitcoin-tx",
"args":
["-create",
"outaddr=1"],
@@ -227,6 +270,18 @@
},
{ "exec": "./bitcoin-tx",
"args":
+ ["-create",
+ "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
+ "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
+ "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":\"0foo\",\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
+ "sign=ALL",
+ "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
+ "return_code": 1,
+ "error_txt": "error: prevtxs internal object typecheck fail",
+ "description": "Tests the check for invalid vout index in prevtxs for sign"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"],
"output_cmp": "txcreateoutpubkey1.hex",
"description": "Creates a new transaction with a single pay-to-pubkey output"