Skip to content

Commit 023f52e

Browse files
committed
Fixed taproot opcodes & buffer overflow
Fixed taproot opcodes validation and buffer overflow
1 parent e2c2e7b commit 023f52e

File tree

6 files changed

+61
-17
lines changed

6 files changed

+61
-17
lines changed

btcdeb.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ int main(int argc, char* const* argv)
242242
}
243243
}
244244

245-
CScript script;
246245
if (script_str) {
247-
if (instance.parse_script(script_str)) {
246+
int witprogver = ((flags & SCRIPT_VERIFY_TAPROOT) != 0 ? 1 : 0);
247+
if (instance.parse_script(witprogver, script_str)) {
248248
if (verbose) btc_logf("valid script\n");
249249
} else {
250250
fprintf(stderr, "invalid script\n");
@@ -300,6 +300,7 @@ int main(int argc, char* const* argv)
300300
p2sh_script = CScript(p2sh_script_payload.begin(), p2sh_script_payload.end());
301301
}
302302
}
303+
303304
if (has_p2sh) {
304305
script_ptrs.push_back(&p2sh_script);
305306
script_headers.push_back("<<< P2SH script >>>");
@@ -316,19 +317,53 @@ int main(int argc, char* const* argv)
316317
script_lines[i++] = strdup(strprintf("#%04d %s", i, s).c_str());
317318
}
318319
}
320+
319321
for (size_t siter = 0; siter < script_ptrs.size(); ++siter) {
320322
CScript* script = script_ptrs[siter];
321323
const std::string& header = script_headers[siter];
322324
if (header != "") script_lines[i++] = strdup(header.c_str());
323325
it = script->begin();
326+
324327
while (script->GetOp(it, opcode, vchPushValue)) {
328+
// log opcode and data
325329
char* pbuf = buf;
326-
pbuf += snprintf(pbuf, 1024, "#%04d ", i);
330+
331+
// Write the line number
332+
int written = snprintf(pbuf, sizeof(buf), "#%04d ", i);
333+
if (written < 0 || written >= (int)sizeof(buf)) {
334+
// Handle error or truncation
335+
// For safety, we can bail out or clamp
336+
written = (int)(sizeof(buf) - 1);
337+
}
338+
pbuf += written;
339+
340+
// Write the opcode
341+
size_t remain = sizeof(buf) - (pbuf - buf);
327342
if (vchPushValue.size() > 0) {
328-
snprintf(pbuf, 1024 + pbuf - buf, "%s", HexStr(std::vector<uint8_t>(vchPushValue.begin(), vchPushValue.end())).c_str());
343+
written = snprintf(
344+
pbuf,
345+
remain,
346+
"%s",
347+
HexStr(std::vector<uint8_t>(vchPushValue.begin(), vchPushValue.end())).c_str()
348+
);
329349
} else {
330-
snprintf(pbuf, 1024 + pbuf - buf, "%s", GetOpName(opcode).c_str());
350+
written = snprintf(
351+
pbuf,
352+
remain,
353+
"%s",
354+
GetOpName(opcode).c_str()
355+
);
331356
}
357+
358+
// Handle error or truncation
359+
if (written < 0 || (size_t)written >= remain) {
360+
// Handle error or truncation
361+
written = (int)(remain - 1);
362+
}
363+
364+
pbuf += written;
365+
366+
// Write the buffer
332367
script_lines[i++] = strdup(buf);
333368
}
334369
}
@@ -349,6 +384,7 @@ int main(int argc, char* const* argv)
349384
}
350385

351386
print_stack(env->stack, true);
387+
352388
return 0;
353389
} else {
354390
kerl_set_history_file(".btcdeb_history");
@@ -371,6 +407,7 @@ int main(int argc, char* const* argv)
371407
if (env->curr_op_seq < count) {
372408
printf("%s\n", script_lines[env->curr_op_seq]);
373409
}
410+
374411
kerl_run("btcdeb> ");
375412
}
376413
}

instance.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ bool Instance::parse_input_transaction(const char* txdata, int select_index) {
9393
return true;
9494
}
9595

96-
bool Instance::parse_script(const char* script_str) {
96+
bool Instance::parse_script(int witprogver, const char* script_str) {
9797
std::vector<unsigned char> scriptData = Value(script_str).data_value();
9898
script = CScript(scriptData.begin(), scriptData.end());
9999
// for (const auto& keymap : COMPILER_CTX.keymap) {
@@ -110,12 +110,12 @@ bool Instance::parse_script(const char* script_str) {
110110
// printf("miniscript failed to parse script; miniscript support disabled\n");
111111
// msenv = nullptr;
112112
// }
113-
return script.HasValidOps();
113+
return witprogver != 0 || script.HasValidOps();
114114
}
115115

116-
bool Instance::parse_script(const std::vector<uint8_t>& script_data) {
116+
bool Instance::parse_script(int witprogver, const std::vector<uint8_t>& script_data) {
117117
script = CScript(script_data.begin(), script_data.end());
118-
return script.HasValidOps();
118+
return witprogver != 0 || script.HasValidOps();
119119
}
120120

121121
bool Instance::parse_pretend_valid_expr(const char* expr) {
@@ -545,7 +545,7 @@ bool Instance::configure_tx_txin() {
545545
}
546546
} else assert(!"should never get here; was a new witprogver added?");
547547

548-
if (parse_script(std::vector<uint8_t>(validation.begin(), validation.end()))) {
548+
if (parse_script(witprogver, std::vector<uint8_t>(validation.begin(), validation.end()))) {
549549
btc_logf("valid script\n");
550550
} else {
551551
fprintf(stderr, "invalid script (witness stack last element)\n");

instance.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ class Instance {
6868
bool parse_transaction(const char* txdata, bool parse_amounts = false);
6969
bool parse_input_transaction(const char* txdata, int select_index = -1);
7070

71-
bool parse_script(const char* script_str);
72-
bool parse_script(const std::vector<uint8_t>& script_data);
71+
bool parse_script(int witprogver, const char* script_str);
72+
bool parse_script(int witprogver, const std::vector<uint8_t>& script_data);
7373

7474
void parse_stack_args(size_t argc, char* const* argv, size_t starting_index);
7575
void parse_stack_args(const std::vector<const char*> args);

script/script.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@
99

1010
#include <string>
1111

12+
#include <tinyformat.h>
13+
1214
std::string GetOpName(opcodetype opcode)
1315
{
16+
if (opcode >= 0x01 && opcode <= 0x4b) {
17+
// It's a push-data opcode for 'opcode' bytes
18+
return strprintf("OP_PUSHBYTES_%d", (int)opcode);
19+
}
20+
1421
switch (opcode)
1522
{
1623
// push value

tap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ int main(int argc, char* const* argv)
265265
for (size_t i = 0; i < script_count; ++i) {
266266
Item scriptData = Value(ca.l[2 + i]).data_value();
267267
CScript script = CScript(scriptData.begin(), scriptData.end());
268-
if (!script.HasValidOps()) {
268+
if (!is_tapscript && !script.HasValidOps()) {
269269
abort("invalid script #%zu: %s", i, HEXC(scriptData));
270270
}
271271
if (!quiet) {

test/signing.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") {
2525
Instance instance;
2626
instance.parse_transaction(TXAMT ":" TXHEX, true);
2727

28-
instance.parse_script(SCRIPT);
28+
instance.parse_script(0, SCRIPT);
2929
// script should have 6 entries
3030
{
3131
size_t count = 0;
@@ -62,7 +62,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") {
6262
#define STACK2X "304502207f874ef00f11dcc9a621acad9354f3fca1bf90c43878f607b7e2d358088487e7022052a01b47b8eef5e1c96a6affdc3dac46fdc11b60612464dc8c5921a852090d2701"
6363
Instance instance;
6464
instance.parse_transaction(TXAMT ":" TXHEX, true);
65-
instance.parse_script(SCRIPT);
65+
instance.parse_script(0, SCRIPT);
6666
const char* argv[] = {STACK1, STACK2X, STACK3};
6767
instance.parse_stack_args(3, (char* const*)argv, 0);
6868
instance.setup_environment();
@@ -86,7 +86,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") {
8686
#define STACK3X "3045022100c56ab2abb17fdf565417228763bc9f2940a6465042fd62fbd9f4c7406345d7f702201cb1a56b45181f8347713627b325ec5df48fc1aee6bdaf937cbb804d7409b10c00"
8787
Instance instance;
8888
instance.parse_transaction(TXAMT ":" TXHEX, true);
89-
instance.parse_script(SCRIPT);
89+
instance.parse_script(0, SCRIPT);
9090
const char* argv[] = {STACK1, STACK2, STACK3X};
9191
instance.parse_stack_args(3, (char* const*)argv, 0);
9292
instance.setup_environment();
@@ -110,7 +110,7 @@ TEST_CASE("Segwit Multisig Signing", "[signing-segwit-multisig]") {
110110
#define TXAMTX "8.947025"
111111
Instance instance;
112112
instance.parse_transaction(TXAMTX ":" TXHEX, true);
113-
instance.parse_script(SCRIPT);
113+
instance.parse_script(0, SCRIPT);
114114
const char* argv[] = {STACK1, STACK2, STACK3};
115115
instance.parse_stack_args(3, (char* const*)argv, 0);
116116
instance.setup_environment();

0 commit comments

Comments
 (0)