Merge #13603: bitcoin-tx: Stricter check for valid integers
57889e688d
bitcoin-tx: Stricter check for valid integers (Daniel Kraft)
Pull request description:
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.
This fixes #13599.
Tree-SHA512: 146a0af275e9f57784e5d0582d3defbac35551b54b6b7232f8a0b20db04aa611125e52aa4512ef2f8ed2cafc2a12fe586f9d10ed66d641cff090288f279b1988
This commit is contained in:
commit
453ae5ec9f
2 changed files with 75 additions and 22 deletions
|
@ -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");
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
"output_cmp": "blanktxv2.json",
|
||||
"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",
|
||||
|
@ -45,6 +51,13 @@
|
|||
"error_txt": "error: Invalid TX input index '31'",
|
||||
"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",
|
||||
|
@ -64,6 +77,13 @@
|
|||
"error_txt": "error: Invalid TX output index '2'",
|
||||
"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",
|
||||
|
@ -76,6 +96,29 @@
|
|||
"output_cmp": "tt-locktime317000-out.json",
|
||||
"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",
|
||||
|
@ -225,6 +268,18 @@
|
|||
"output_cmp": "txcreatesignv2.hex",
|
||||
"description": "Creates a new transaction with a single input and a single output, and then signs the transaction"
|
||||
},
|
||||
{ "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"],
|
||||
|
|
Loading…
Reference in a new issue