Skip to content

Commit 54f1022

Browse files
committed
Merge pull request #3843
787ee0c Check redeemScript size does not exceed 520 byte limit (Peter Todd) 4d79098 Increase IsStandard() scriptSig length (Peter Todd) f80cffa Do not trigger a DoS ban if SCRIPT_VERIFY_NULLDUMMY fails (Peter Todd) 6380180 Add rejection of non-null CHECKMULTISIG dummy values (Peter Todd) 29c1749 Let tx (in)valid tests use any SCRIPT_VERIFY flag (Peter Todd) 68f7d1d Create (MANDATORY|STANDARD)_SCRIPT_VERIFY_FLAGS constants (Peter Todd)
2 parents 1c0319b + 787ee0c commit 54f1022

File tree

12 files changed

+211
-71
lines changed

12 files changed

+211
-71
lines changed

src/keystore.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
3333

3434
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
3535
{
36+
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
37+
return error("CBasicKeyStore::AddCScript() : redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
38+
3639
LOCK(cs_KeyStore);
3740
mapScripts[redeemScript.GetID()] = redeemScript;
3841
return true;

src/main.cpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -515,10 +515,14 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
515515

516516
BOOST_FOREACH(const CTxIn& txin, tx.vin)
517517
{
518-
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
519-
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
520-
// ~65-byte public keys, plus a few script ops.
521-
if (txin.scriptSig.size() > 500) {
518+
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
519+
// keys. (remember the 520 byte limit on redeemScript size) That works
520+
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)=1624
521+
// bytes of scriptSig, which we round off to 1650 bytes for some minor
522+
// future-proofing. That's also enough to spend a 20-of-20
523+
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
524+
// considered standard)
525+
if (txin.scriptSig.size() > 1650) {
522526
reason = "scriptsig-size";
523527
return false;
524528
}
@@ -945,7 +949,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
945949

946950
// Check against previous transactions
947951
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
948-
if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC))
952+
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS))
949953
{
950954
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString());
951955
}
@@ -1588,14 +1592,26 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
15881592
pvChecks->push_back(CScriptCheck());
15891593
check.swap(pvChecks->back());
15901594
} else if (!check()) {
1591-
if (flags & SCRIPT_VERIFY_STRICTENC) {
1592-
// For now, check whether the failure was caused by non-canonical
1593-
// encodings or not; if so, don't trigger DoS protection.
1594-
CScriptCheck check(coins, tx, i, flags & (~SCRIPT_VERIFY_STRICTENC), 0);
1595+
if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
1596+
// Check whether the failure was caused by a
1597+
// non-mandatory script verification check, such as
1598+
// non-standard DER encodings or non-null dummy
1599+
// arguments; if so, don't trigger DoS protection to
1600+
// avoid splitting the network between upgraded and
1601+
// non-upgraded nodes.
1602+
CScriptCheck check(coins, tx, i,
1603+
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, 0);
15951604
if (check())
1596-
return state.Invalid(false, REJECT_NONSTANDARD, "non-canonical");
1605+
return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag");
15971606
}
1598-
return state.DoS(100,false, REJECT_NONSTANDARD, "non-canonical");
1607+
// Failures of other flags indicate a transaction that is
1608+
// invalid in new blocks, e.g. a invalid P2SH. We DoS ban
1609+
// such nodes as they are not following the protocol. That
1610+
// said during an upgrade careful thought should be taken
1611+
// as to the correct behavior - we may want to continue
1612+
// peering with non-upgraded nodes even after a soft-fork
1613+
// super-majority vote has passed.
1614+
return state.DoS(100,false, REJECT_INVALID, "mandatory-script-verify-flag-failed");
15991615
}
16001616
}
16011617
}

src/main.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ inline bool AllowFree(double dPriority)
309309
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
310310
// instead of being performed inline.
311311
bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
312-
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
312+
unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS,
313313
std::vector<CScriptCheck> *pvChecks = NULL);
314314

315315
// Apply the effects of this transaction on the UTXO set represented by view

src/miner.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
276276
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
277277
continue;
278278

279+
// Note that flags: we don't want to set mempool/IsStandard()
280+
// policy here, but we still have to ensure that the block we
281+
// create only contains transactions that are valid in new blocks.
279282
CValidationState state;
280-
if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH))
283+
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS))
281284
continue;
282285

283286
CTxUndo txundo;

src/rpcmisc.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ Value validateaddress(const Array& params, bool fHelp)
176176
//
177177
// Used by addmultisigaddress / createmultisig:
178178
//
179-
CScript _createmultisig(const Array& params)
179+
CScript _createmultisig_redeemScript(const Array& params)
180180
{
181181
int nRequired = params[0].get_int();
182182
const Array& keys = params[1].get_array();
@@ -228,6 +228,11 @@ CScript _createmultisig(const Array& params)
228228
}
229229
CScript result;
230230
result.SetMultisig(nRequired, pubkeys);
231+
232+
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
233+
throw runtime_error(
234+
strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
235+
231236
return result;
232237
}
233238

@@ -263,7 +268,7 @@ Value createmultisig(const Array& params, bool fHelp)
263268
}
264269

265270
// Construct using pay-to-script-hash:
266-
CScript inner = _createmultisig(params);
271+
CScript inner = _createmultisig_redeemScript(params);
267272
CScriptID innerID = inner.GetID();
268273
CBitcoinAddress address(innerID);
269274

src/rpcrawtransaction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
717717
{
718718
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
719719
}
720-
if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
720+
if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS, 0))
721721
fComplete = false;
722722
}
723723

src/rpcwallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ Value sendmany(const Array& params, bool fHelp)
871871
}
872872

873873
// Defined in rpcmisc.cpp
874-
extern CScript _createmultisig(const Array& params);
874+
extern CScript _createmultisig_redeemScript(const Array& params);
875875

876876
Value addmultisigaddress(const Array& params, bool fHelp)
877877
{
@@ -908,7 +908,7 @@ Value addmultisigaddress(const Array& params, bool fHelp)
908908
strAccount = AccountFromValue(params[2]);
909909

910910
// Construct using pay-to-script-hash:
911-
CScript inner = _createmultisig(params);
911+
CScript inner = _createmultisig_redeemScript(params);
912912
CScriptID innerID = inner.GetID();
913913
pwalletMain->AddCScript(inner);
914914

src/script.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -923,8 +923,22 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
923923
fSuccess = false;
924924
}
925925

926-
while (i-- > 0)
926+
// Clean up stack of actual arguments
927+
while (i-- > 1)
927928
popstack(stack);
929+
930+
// A bug causes CHECKMULTISIG to consume one extra argument
931+
// whose contents were not checked in any way.
932+
//
933+
// Unfortunately this is a potential source of mutability,
934+
// so optionally verify it is exactly equal to zero prior
935+
// to removing it from the stack.
936+
if (stack.size() < 1)
937+
return false;
938+
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size())
939+
return error("CHECKMULTISIG dummy argument not null");
940+
popstack(stack);
941+
928942
stack.push_back(fSuccess ? vchTrue : vchFalse);
929943

930944
if (opcode == OP_CHECKMULTISIGVERIFY)
@@ -1659,7 +1673,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
16591673
}
16601674

16611675
// Test solution
1662-
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0);
1676+
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
16631677
}
16641678

16651679
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)

src/script.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,28 @@ enum
190190
SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
191191
SCRIPT_VERIFY_EVEN_S = (1U << 2), // enforce even S values in signatures (depends on STRICTENC)
192192
SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
193+
SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
193194
};
194195

196+
// Mandatory script verification flags that all new blocks must comply with for
197+
// them to be valid. (but old blocks may not comply with) Currently just P2SH,
198+
// but in the future other flags may be added, such as a soft-fork to enforce
199+
// strict DER encoding.
200+
//
201+
// Failing one of these tests may trigger a DoS ban - see CheckInputs() for
202+
// details.
203+
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
204+
205+
// Standard script verification flags that standard transactions will comply
206+
// with. However scripts violating these flags may still be present in valid
207+
// blocks and we must accept those blocks.
208+
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
209+
SCRIPT_VERIFY_STRICTENC |
210+
SCRIPT_VERIFY_NULLDUMMY;
211+
212+
// For convenience, standard but not mandatory verify flags.
213+
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
214+
195215
enum txnouttype
196216
{
197217
TX_NONSTANDARD,

0 commit comments

Comments
 (0)