diff --git a/bitcoin/script/miniscript.h b/bitcoin/script/miniscript.h index 7d4aa00..59aa130 100644 --- a/bitcoin/script/miniscript.h +++ b/bitcoin/script/miniscript.h @@ -1634,58 +1634,69 @@ inline NodeRef DecodeScript(I& in, I last, const Ctx& ctx) break; } case DecodeContext::SWAP: { - if (in >= last || in[0].first != OP_SWAP) return {}; + if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {}; ++in; constructed.back() = MakeNodeRef(NodeType::WRAP_S, Vector(std::move(constructed.back()))); break; } case DecodeContext::ALT: { - if (in >= last || in[0].first != OP_TOALTSTACK) return {}; + if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {}; ++in; constructed.back() = MakeNodeRef(NodeType::WRAP_A, Vector(std::move(constructed.back()))); break; } case DecodeContext::CHECK: { + if (constructed.empty()) return {}; constructed.back() = MakeNodeRef(NodeType::WRAP_C, Vector(std::move(constructed.back()))); break; } case DecodeContext::DUP_IF: { + if (constructed.empty()) return {}; constructed.back() = MakeNodeRef(NodeType::WRAP_D, Vector(std::move(constructed.back()))); break; } case DecodeContext::VERIFY: { + if (constructed.empty()) return {}; constructed.back() = MakeNodeRef(NodeType::WRAP_V, Vector(std::move(constructed.back()))); break; } case DecodeContext::NON_ZERO: { + if (constructed.empty()) return {}; constructed.back() = MakeNodeRef(NodeType::WRAP_J, Vector(std::move(constructed.back()))); break; } case DecodeContext::ZERO_NOTEQUAL: { + if (constructed.empty()) return {}; constructed.back() = MakeNodeRef(NodeType::WRAP_N, Vector(std::move(constructed.back()))); break; } case DecodeContext::AND_V: { + if (constructed.size() < 2) return {}; BuildBack(NodeType::AND_V, constructed, /* reverse */ true); break; } case DecodeContext::AND_B: { + if (constructed.size() < 2) return {}; BuildBack(NodeType::AND_B, constructed, /* reverse */ true); break; } case DecodeContext::OR_B: { + if (constructed.size() < 2) return {}; BuildBack(NodeType::OR_B, constructed, /* reverse */ true); break; } case DecodeContext::OR_C: { + if (constructed.size() < 2) return {}; BuildBack(NodeType::OR_C, constructed, /* reverse */ true); break; } case DecodeContext::OR_D: { + if (constructed.size() < 2) return {}; BuildBack(NodeType::OR_D, constructed, /* reverse */ true); break; } case DecodeContext::ANDOR: { + if (constructed.size() < 3) return {}; NodeRef left = std::move(constructed.back()); constructed.pop_back(); NodeRef right = std::move(constructed.back()); @@ -1708,7 +1719,7 @@ inline NodeRef DecodeScript(I& in, I last, const Ctx& ctx) break; } case DecodeContext::THRESH_E: { - if (k < 1 || k > n) return {}; + if (k < 1 || k > n || constructed.size() < static_cast(n)) return {}; std::vector> subs; for (int i = 0; i < n; ++i) { NodeRef sub = std::move(constructed.back()); diff --git a/bitcoin/test/fuzz/miniscript_decode.cpp b/bitcoin/test/fuzz/miniscript_decode.cpp new file mode 100644 index 0000000..4cc0a1b --- /dev/null +++ b/bitcoin/test/fuzz/miniscript_decode.cpp @@ -0,0 +1,72 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include