From bc46fd1dcbca89eddd66f540f8470b4fa74b71eb Mon Sep 17 00:00:00 2001 From: BlobMaster41 <96896824+BlobMaster41@users.noreply.github.com> Date: Sun, 16 Jun 2024 02:43:02 -0400 Subject: [PATCH 1/3] Update script.h --- script/script.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/script.h b/script/script.h index 52e933a1..e4c99de1 100644 --- a/script/script.h +++ b/script/script.h @@ -209,7 +209,7 @@ enum opcodetype }; // Maximum value that an opcode can be -static const unsigned int MAX_OPCODE = OP_NOP10; +static const unsigned int MAX_OPCODE = OP_CHECKSIGADD; std::string GetOpName(opcodetype opcode); From 023f52e85991af130ae8bffeb2fb6673213aea90 Mon Sep 17 00:00:00 2001 From: BlobMaster41 <96896824+BlobMaster41@users.noreply.github.com> Date: Sun, 16 Jun 2024 02:43:02 -0400 Subject: [PATCH 2/3] Fixed taproot opcodes & buffer overflow Fixed taproot opcodes validation and buffer overflow --- btcdeb.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++----- instance.cpp | 10 +++++----- instance.h | 4 ++-- script/script.cpp | 7 +++++++ tap.cpp | 2 +- test/signing.cpp | 8 ++++---- 6 files changed, 61 insertions(+), 17 deletions(-) diff --git a/btcdeb.cpp b/btcdeb.cpp index 7200618a..8ddb23fa 100644 --- a/btcdeb.cpp +++ b/btcdeb.cpp @@ -242,9 +242,9 @@ int main(int argc, char* const* argv) } } - CScript script; if (script_str) { - if (instance.parse_script(script_str)) { + int witprogver = ((flags & SCRIPT_VERIFY_TAPROOT) != 0 ? 1 : 0); + if (instance.parse_script(witprogver, script_str)) { if (verbose) btc_logf("valid script\n"); } else { fprintf(stderr, "invalid script\n"); @@ -300,6 +300,7 @@ int main(int argc, char* const* argv) p2sh_script = CScript(p2sh_script_payload.begin(), p2sh_script_payload.end()); } } + if (has_p2sh) { script_ptrs.push_back(&p2sh_script); script_headers.push_back("<<< P2SH script >>>"); @@ -316,19 +317,53 @@ int main(int argc, char* const* argv) script_lines[i++] = strdup(strprintf("#%04d %s", i, s).c_str()); } } + for (size_t siter = 0; siter < script_ptrs.size(); ++siter) { CScript* script = script_ptrs[siter]; const std::string& header = script_headers[siter]; if (header != "") script_lines[i++] = strdup(header.c_str()); it = script->begin(); + while (script->GetOp(it, opcode, vchPushValue)) { + // log opcode and data char* pbuf = buf; - pbuf += snprintf(pbuf, 1024, "#%04d ", i); + + // Write the line number + int written = snprintf(pbuf, sizeof(buf), "#%04d ", i); + if (written < 0 || written >= (int)sizeof(buf)) { + // Handle error or truncation + // For safety, we can bail out or clamp + written = (int)(sizeof(buf) - 1); + } + pbuf += written; + + // Write the opcode + size_t remain = sizeof(buf) - (pbuf - buf); if (vchPushValue.size() > 0) { - snprintf(pbuf, 1024 + pbuf - buf, "%s", HexStr(std::vector(vchPushValue.begin(), vchPushValue.end())).c_str()); + written = snprintf( + pbuf, + remain, + "%s", + HexStr(std::vector(vchPushValue.begin(), vchPushValue.end())).c_str() + ); } else { - snprintf(pbuf, 1024 + pbuf - buf, "%s", GetOpName(opcode).c_str()); + written = snprintf( + pbuf, + remain, + "%s", + GetOpName(opcode).c_str() + ); } + + // Handle error or truncation + if (written < 0 || (size_t)written >= remain) { + // Handle error or truncation + written = (int)(remain - 1); + } + + pbuf += written; + + // Write the buffer script_lines[i++] = strdup(buf); } } @@ -349,6 +384,7 @@ int main(int argc, char* const* argv) } print_stack(env->stack, true); + return 0; } else { kerl_set_history_file(".btcdeb_history"); @@ -371,6 +407,7 @@ int main(int argc, char* const* argv) if (env->curr_op_seq < count) { printf("%s\n", script_lines[env->curr_op_seq]); } + kerl_run("btcdeb> "); } } diff --git a/instance.cpp b/instance.cpp index d6ddf333..1f18fb63 100644 --- a/instance.cpp +++ b/instance.cpp @@ -93,7 +93,7 @@ bool Instance::parse_input_transaction(const char* txdata, int select_index) { return true; } -bool Instance::parse_script(const char* script_str) { +bool Instance::parse_script(int witprogver, const char* script_str) { std::vector scriptData = Value(script_str).data_value(); script = CScript(scriptData.begin(), scriptData.end()); // for (const auto& keymap : COMPILER_CTX.keymap) { @@ -110,12 +110,12 @@ bool Instance::parse_script(const char* script_str) { // printf("miniscript failed to parse script; miniscript support disabled\n"); // msenv = nullptr; // } - return script.HasValidOps(); + return witprogver != 0 || script.HasValidOps(); } -bool Instance::parse_script(const std::vector& script_data) { +bool Instance::parse_script(int witprogver, const std::vector& script_data) { script = CScript(script_data.begin(), script_data.end()); - return script.HasValidOps(); + return witprogver != 0 || script.HasValidOps(); } bool Instance::parse_pretend_valid_expr(const char* expr) { @@ -545,7 +545,7 @@ bool Instance::configure_tx_txin() { } } else assert(!"should never get here; was a new witprogver added?"); - if (parse_script(std::vector(validation.begin(), validation.end()))) { + if (parse_script(witprogver, std::vector(validation.begin(), validation.end()))) { btc_logf("valid script\n"); } else { fprintf(stderr, "invalid script (witness stack last element)\n"); diff --git a/instance.h b/instance.h index 6b8e75c0..6e183dad 100644 --- a/instance.h +++ b/instance.h @@ -68,8 +68,8 @@ class Instance { bool parse_transaction(const char* txdata, bool parse_amounts = false); bool parse_input_transaction(const char* txdata, int select_index = -1); - bool parse_script(const char* script_str); - bool parse_script(const std::vector& script_data); + bool parse_script(int witprogver, const char* script_str); + bool parse_script(int witprogver, const std::vector& script_data); void parse_stack_args(size_t argc, char* const* argv, size_t starting_index); void parse_stack_args(const std::vector args); diff --git a/script/script.cpp b/script/script.cpp index 88b4bc2f..a01da616 100644 --- a/script/script.cpp +++ b/script/script.cpp @@ -9,8 +9,15 @@ #include +#include + std::string GetOpName(opcodetype opcode) { + if (opcode >= 0x01 && opcode <= 0x4b) { + // It's a push-data opcode for 'opcode' bytes + return strprintf("OP_PUSHBYTES_%d", (int)opcode); + } + switch (opcode) { // push value diff --git a/tap.cpp b/tap.cpp index 991571c5..4e01d8bc 100644 --- a/tap.cpp +++ b/tap.cpp @@ -265,7 +265,7 @@ int main(int argc, char* const* argv) for (size_t i = 0; i < script_count; ++i) { Item scriptData = Value(ca.l[2 + i]).data_value(); CScript script = CScript(scriptData.begin(), scriptData.end()); - if (!script.HasValidOps()) { + if (!is_tapscript && !script.HasValidOps()) { abort("invalid script #%zu: %s", i, HEXC(scriptData)); } if (!quiet) { diff --git a/test/signing.cpp b/test/signing.cpp index aeca792c..02651f30 100644 --- a/test/signing.cpp +++ b/test/signing.cpp @@ -25,7 +25,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") { Instance instance; instance.parse_transaction(TXAMT ":" TXHEX, true); - instance.parse_script(SCRIPT); + instance.parse_script(0, SCRIPT); // script should have 6 entries { size_t count = 0; @@ -62,7 +62,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") { #define STACK2X "304502207f874ef00f11dcc9a621acad9354f3fca1bf90c43878f607b7e2d358088487e7022052a01b47b8eef5e1c96a6affdc3dac46fdc11b60612464dc8c5921a852090d2701" Instance instance; instance.parse_transaction(TXAMT ":" TXHEX, true); - instance.parse_script(SCRIPT); + instance.parse_script(0, SCRIPT); const char* argv[] = {STACK1, STACK2X, STACK3}; instance.parse_stack_args(3, (char* const*)argv, 0); instance.setup_environment(); @@ -86,7 +86,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") { #define STACK3X "3045022100c56ab2abb17fdf565417228763bc9f2940a6465042fd62fbd9f4c7406345d7f702201cb1a56b45181f8347713627b325ec5df48fc1aee6bdaf937cbb804d7409b10c00" Instance instance; instance.parse_transaction(TXAMT ":" TXHEX, true); - instance.parse_script(SCRIPT); + instance.parse_script(0, SCRIPT); const char* argv[] = {STACK1, STACK2, STACK3X}; instance.parse_stack_args(3, (char* const*)argv, 0); instance.setup_environment(); @@ -110,7 +110,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") { #define TXAMTX "8.947025" Instance instance; instance.parse_transaction(TXAMTX ":" TXHEX, true); - instance.parse_script(SCRIPT); + instance.parse_script(0, SCRIPT); const char* argv[] = {STACK1, STACK2, STACK3}; instance.parse_stack_args(3, (char* const*)argv, 0); instance.setup_environment(); From d35a18fd82678c045ecc347c8fb3518e29520f02 Mon Sep 17 00:00:00 2001 From: Anakun <96896824+BlobMaster41@users.noreply.github.com> Date: Mon, 24 Mar 2025 03:27:38 +0400 Subject: [PATCH 3/3] Reverted last fix --- script/script.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/script.h b/script/script.h index e4c99de1..52e933a1 100644 --- a/script/script.h +++ b/script/script.h @@ -209,7 +209,7 @@ enum opcodetype }; // Maximum value that an opcode can be -static const unsigned int MAX_OPCODE = OP_CHECKSIGADD; +static const unsigned int MAX_OPCODE = OP_NOP10; std::string GetOpName(opcodetype opcode);