From 4de5cca7e7a0a7104dae8d414add33f6e9562e4a Mon Sep 17 00:00:00 2001 From: Nsable-sh Date: Fri, 7 Aug 2026 10:55:54 -0300 Subject: fuzz: add script parser harness (#5) --- src/Makefile | 27 +++++++++++++++++++----- src/fuzz_script.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/fuzz_script.cpp (limited to 'src') diff --git a/src/Makefile b/src/Makefile index ac0226e..cc52fd6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -121,8 +121,9 @@ NODE_LIBS = -L$(SECP_LIB) -lsecp256k1 \ NODE_ONLY_OBJS = $(patsubst obj/%,obj-node/%,$(NODE_OBJS)) \ obj-node/main_gui.o obj-node/headless.o -FUZZ_OBJS = $(patsubst obj/%,obj-fuzz/%,$(NODE_OBJS)) \ - obj-fuzz/fuzz_net_message.o +FUZZ_BASE_OBJS = $(patsubst obj/%,obj-fuzz/%,$(NODE_OBJS)) +FUZZ_NET_MESSAGE_OBJS = $(FUZZ_BASE_OBJS) obj-fuzz/fuzz_net_message.o +FUZZ_SCRIPT_OBJS = $(FUZZ_BASE_OBJS) obj-fuzz/fuzz_script.o obj-node/%.o: %.cpp $(HEADERS) @mkdir -p obj-node @@ -148,19 +149,35 @@ obj-fuzz/fuzz_net_message.o: fuzz_net_message.cpp $(HEADERS) @mkdir -p obj-fuzz $(FUZZ_CXX) -c $(FUZZ_CXXFLAGS) -DBITFLASH_FUZZ -o $@ $< -fuzz-net-message: $(FUZZ_OBJS) +obj-fuzz/fuzz_script.o: fuzz_script.cpp $(HEADERS) + @mkdir -p obj-fuzz + $(FUZZ_CXX) -c $(FUZZ_CXXFLAGS) -DBITFLASH_FUZZ -o $@ $< + +fuzz-net-message: $(FUZZ_NET_MESSAGE_OBJS) $(FUZZ_CXX) $(filter-out -fsanitize=fuzzer-no-link%,$(FUZZ_CXXFLAGS)) \ $(FUZZ_LDFLAGS) -o $@ $^ $(NODE_LIBS) @echo "Built: fuzz-net-message" +fuzz-script: $(FUZZ_SCRIPT_OBJS) + $(FUZZ_CXX) $(filter-out -fsanitize=fuzzer-no-link%,$(FUZZ_CXXFLAGS)) \ + $(FUZZ_LDFLAGS) -o $@ $^ $(NODE_LIBS) + @echo "Built: fuzz-script" + fuzz-net-message-smoke: fuzz-net-message @mkdir -p ../work/fuzz-corpus/net-message @printf '\277\040\134\375ping\000\000\000\000\000\000\000\000\000\000\000\000' > ../work/fuzz-corpus/net-message/ping-header @printf '\277\040\134\375version\000\000\000\000\000\000\000\000\000' > ../work/fuzz-corpus/net-message/version-header ./fuzz-net-message -runs=128 ../work/fuzz-corpus/net-message +fuzz-script-smoke: fuzz-script + @mkdir -p ../work/fuzz-corpus/script + @printf '\000\121' > ../work/fuzz-corpus/script/op-true + @printf '\001\166\251\024\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\210\254' > ../work/fuzz-corpus/script/p2pkh-shape + @printf '\000\115\377\377' > ../work/fuzz-corpus/script/truncated-pushdata2 + ./fuzz-script -runs=128 ../work/fuzz-corpus/script + clean: - rm -rf obj obj-node obj-fuzz bitflash bitflash-node fuzz-net-message test_bip32 + rm -rf obj obj-node obj-fuzz bitflash bitflash-node fuzz-net-message fuzz-script test_bip32 test_bip32: test_bip32.cpp bip32.cpp bip32.h bip39_english.h $(CXX) $(CXXFLAGS) -o $@ test_bip32.cpp bip32.cpp -lssl -lcrypto @@ -175,4 +192,4 @@ tests: test_bip32 bitflash-node ./bitflash-node -selftest=net-message ./bitflash-node -selftest=consensus-limits -.PHONY: tests fuzz-net-message-smoke +.PHONY: tests fuzz-net-message-smoke fuzz-script-smoke diff --git a/src/fuzz_script.cpp b/src/fuzz_script.cpp new file mode 100644 index 0000000..28c84f6 --- /dev/null +++ b/src/fuzz_script.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2026 Bitflash developers +// Distributed under the MIT/X11 software license. +// +// libFuzzer harness for raw script parsing and evaluation. It keeps the +// target deliberately small: arbitrary bytes become one CScript, then the +// parser, standard-script extractors and EvalScript all see that same input. + +#include "headers_core.h" + +#include +#include + +// Stand-ins normally supplied by the GUI/headless entry objects. +map mapAddressBook; +bool gPoolServerRunning = false; +void MainFrameRepaint() {} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + if (size < 1 || size > 4096) + return 0; + + try + { + int nHashType = data[0]; + const unsigned char* pbegin = data + 1; + const unsigned char* pend = data + size; + CScript script(pbegin, pend); + + CScript::const_iterator pc = script.begin(); + opcodetype opcode; + vector vchPush; + while (pc < script.end()) + { + if (!script.GetOp(pc, opcode, vchPush)) + break; + } + + script.GetSigOpCount(); + script.ToString(); + + vector vchPubKey; + ExtractPubKey(script, false, vchPubKey); + uint160 hash160; + ExtractHash160(script, hash160); + + CTransaction tx; + tx.vin.push_back(CTxIn(COutPoint(), CScript())); + tx.vout.push_back(CTxOut(0, CScript())); + + vector > stack; + EvalScript(script, tx, 0, nHashType, &stack); + } + catch (...) + { + } + + return 0; +} -- cgit v1.2.3