diff options
-rwxr-xr-x | contrib/macdeploy/macdeployqtplus | 10 | ||||
-rw-r--r-- | depends/packages/native_comparisontool.mk | 6 | ||||
-rw-r--r-- | src/core.cpp | 53 | ||||
-rw-r--r-- | src/core.h | 6 | ||||
-rw-r--r-- | src/init.cpp | 9 | ||||
-rw-r--r-- | src/main.cpp | 21 |
6 files changed, 74 insertions, 31 deletions
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 1b50981f0a..8f826ace09 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -292,7 +292,7 @@ def copyFramework(framework, path, verbose): fromResourcesDir = framework.sourceResourcesDirectory if os.path.exists(fromResourcesDir): toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory) - shutil.copytree(fromResourcesDir, toResourcesDir) + shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True) if verbose >= 3: print "Copied resources:", fromResourcesDir print " to:", toResourcesDir @@ -301,7 +301,7 @@ def copyFramework(framework, path, verbose): fromContentsDir = framework.sourceContentsDirectory if os.path.exists(fromContentsDir): toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory) - shutil.copytree(fromContentsDir, toContentsDir) + shutil.copytree(fromContentsDir, toContentsDir, symlinks=True) contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory) if verbose >= 3: print "Copied Contents:", fromContentsDir @@ -310,7 +310,7 @@ def copyFramework(framework, path, verbose): qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib") qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib") if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath): - shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath) + shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True) if verbose >= 3: print "Copied for libQtGui:", qtMenuNibSourcePath print " to:", qtMenuNibDestinationPath @@ -584,7 +584,7 @@ if verbose >= 3: print app_bundle, "->", target os.mkdir("dist") -shutil.copytree(app_bundle, target) +shutil.copytree(app_bundle, target, symlinks=True) applicationBundle = ApplicationBundleInfo(target) @@ -671,7 +671,7 @@ for p in config.add_resources: if verbose >= 3: print p, "->", t if os.path.isdir(p): - shutil.copytree(p, t) + shutil.copytree(p, t, symlinks=True) else: shutil.copy2(p, t) diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk index d9f7722190..4c40f8b123 100644 --- a/depends/packages/native_comparisontool.mk +++ b/depends/packages/native_comparisontool.mk @@ -1,8 +1,8 @@ package=native_comparisontool -$(package)_version=adfd3de7 -$(package)_download_path=https://github.com/TheBlueMatt/test-scripts/raw/10222bfdace65a0c5f3bd4a766eeb6b3a8b869fb/ +$(package)_version=5caed78 +$(package)_download_path=https://github.com/TheBlueMatt/test-scripts/raw/2d76ce92d68e6746988adde731318605a70e252c $(package)_file_name=pull-tests-$($(package)_version).jar -$(package)_sha256_hash=fd2282b112e35f339dbe3729b08a04834ad719f8c9c10eeec1178465e6d36a18 +$(package)_sha256_hash=b55a98828b17060e327c5dabe5e4631898f422c0cba07c46170930a9eaf5e7c0 $(package)_install_dirname=BitcoindComparisonTool_jar $(package)_install_filename=BitcoindComparisonTool.jar diff --git a/src/core.cpp b/src/core.cpp index 1489d77bb3..380b1c38e0 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -224,29 +224,66 @@ uint256 CBlockHeader::GetHash() const return Hash(BEGIN(nVersion), END(nNonce)); } -uint256 CBlock::BuildMerkleTree() const +uint256 CBlock::BuildMerkleTree(bool* fMutated) const { - // WARNING! If you're reading this because you're learning about crypto - // and/or designing a new system that will use merkle trees, keep in mind - // that the following merkle tree algorithm has a serious flaw related to - // duplicate txids, resulting in a vulnerability. (CVE-2012-2459) Bitcoin - // has since worked around the flaw, but for new applications you should - // use something different; don't just copy-and-paste this code without - // understanding the problem first. + /* WARNING! If you're reading this because you're learning about crypto + and/or designing a new system that will use merkle trees, keep in mind + that the following merkle tree algorithm has a serious flaw related to + duplicate txids, resulting in a vulnerability (CVE-2012-2459). + + The reason is that if the number of hashes in the list at a given time + is odd, the last one is duplicated before computing the next level (which + is unusual in Merkle trees). This results in certain sequences of + transactions leading to the same merkle root. For example, these two + trees: + + A A + / \ / \ + B C B C + / \ | / \ / \ + D E F D E F F + / \ / \ / \ / \ / \ / \ / \ + 1 2 3 4 5 6 1 2 3 4 5 6 5 6 + + for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and + 6 are repeated) result in the same root hash A (because the hash of both + of (F) and (F,F) is C). + + The vulnerability results from being able to send a block with such a + transaction list, with the same merkle root, and the same block hash as + the original without duplication, resulting in failed validation. If the + receiving node proceeds to mark that block as permanently invalid + however, it will fail to accept further unmodified (and thus potentially + valid) versions of the same block. We defend against this by detecting + the case where we would hash two identical hashes at the end of the list + together, and treating that identically to the block having an invalid + merkle root. Assuming no double-SHA256 collisions, this will detect all + known ways of changing the transactions without affecting the merkle + root. + */ vMerkleTree.clear(); + vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. BOOST_FOREACH(const CTransaction& tx, vtx) vMerkleTree.push_back(tx.GetHash()); int j = 0; + bool mutated = false; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { for (int i = 0; i < nSize; i += 2) { int i2 = std::min(i+1, nSize-1); + if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) { + // Two identical hashes at the end of the list at a particular level. + mutated = true; + } vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); } j += nSize; } + if (fMutated) { + *fMutated = mutated; + } return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); } diff --git a/src/core.h b/src/core.h index e8435c8b0d..a348293578 100644 --- a/src/core.h +++ b/src/core.h @@ -529,7 +529,11 @@ public: return block; } - uint256 BuildMerkleTree() const; + // Build the in-memory merkle tree for this block and return the merkle root. + // If non-NULL, *mutated is set to whether mutation was detected in the merkle + // tree (a duplication of transactions in the block leading to an identical + // merkle root). + uint256 BuildMerkleTree(bool* mutated = NULL) const; std::vector<uint256> GetMerkleBranch(int nIndex) const; static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex); diff --git a/src/init.cpp b/src/init.cpp index 503df7ad3f..980c589b29 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -45,7 +45,7 @@ using namespace boost; using namespace std; #ifdef ENABLE_WALLET -CWallet* pwalletMain; +CWallet* pwalletMain = NULL; #endif #ifdef WIN32 @@ -109,7 +109,7 @@ bool ShutdownRequested() return fRequestShutdown; } -static CCoinsViewDB *pcoinsdbview; +static CCoinsViewDB *pcoinsdbview = NULL; void Shutdown() { @@ -165,8 +165,8 @@ void Shutdown() #endif UnregisterAllWallets(); #ifdef ENABLE_WALLET - if (pwalletMain) - delete pwalletMain; + delete pwalletMain; + pwalletMain = NULL; #endif LogPrintf("%s: done\n", __func__); } @@ -701,6 +701,7 @@ bool AppInit2(boost::thread_group& threadGroup) fIsBareMultisigStd = GetArg("-permitbaremultisig", true) != 0; // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down.")); diff --git a/src/main.cpp b/src/main.cpp index 5a5c700574..a3e36ff872 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,7 @@ #include "txmempool.h" #include "ui_interface.h" #include "util.h" +#include "utilmoneystr.h" #include <sstream> @@ -1316,7 +1317,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach bool CScriptCheck::operator()() const { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags)) - return error("CScriptCheck() : %s VerifySignature failed", ptxTo->GetHash().ToString()); + return error("CScriptCheck() : %s:%d VerifySignature failed", ptxTo->GetHash().ToString(), nIn); return true; } @@ -1361,7 +1362,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi } if (nValueIn < tx.GetValueOut()) - return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString()), + return state.DoS(100, error("CheckInputs() : %s value in (%s) < value out (%s)", + tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())), REJECT_INVALID, "bad-txns-in-belowout"); // Tally transaction fees @@ -2236,13 +2238,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo if (!CheckTransaction(tx, state)) return error("CheckBlock() : CheckTransaction failed"); - // Check for duplicate txids. This is caught by ConnectInputs(), - // but catching it earlier avoids a potential DoS attack: - set<uint256> uniqueTx; - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - uniqueTx.insert(tx.GetHash()); - } - if (uniqueTx.size() != block.vtx.size()) + // Check for merkle tree malleability (CVE-2012-2459): repeating sequences + // of transactions in a block without affecting the merkle root of a block, + // while still invalidating it. + bool mutated; + uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); + if (mutated) return state.DoS(100, error("CheckBlock() : duplicate transaction"), REJECT_INVALID, "bad-txns-duplicate", true); @@ -2256,7 +2257,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo REJECT_INVALID, "bad-blk-sigops", true); // Check merkle root - if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree()) + if (fCheckMerkleRoot && block.hashMerkleRoot != hashMerkleRoot2) return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), REJECT_INVALID, "bad-txnmrklroot", true); |