build: add fuzzing infrastructure for security testing
What changed, and why it matters
This commit only adds new build options and a test harness for fuzzing (automated security testing). It does not change any existing library code that handles PSBTs or other data, so it cannot by itself introduce a security vulnerability or fix one. It is purely an infrastructure addition to help future security testing.
No security action required; review is informational. If fuzzing reveals crashes, those should be triaged and patched separately.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces –enable-fuzzing, –enable-address-sanitizer, and –enable-ub-sanitizer configure/CMake options, plus a new fuzz/fuzz_psbt.c harness that calls wally_psbt_from_bytes with strict, loose, and zero flags and round-trips successful parses through wally_psbt_get_length/wally_psbt_to_bytes. No production source files under src/ are modified. The change is additive testing infrastructure only.
Changed components
build system (configure.ac, _CMakeLists.txt, Makefile.am)documentation (README.md)new fuzzing harness (fuzz/fuzz_psbt.c, fuzz/Makefile.am)Inspect captured patch +108 / −0
diff --git a/.gitignore b/.gitignore
index 77dc28f..ba5fad5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,8 @@ config.sub
configure
depcomp
dist
+fuzz/fuzz_*
+!fuzz/fuzz_*.c
install-sh
libtool
ltmain.sh
diff --git a/Makefile.am b/Makefile.am
index c437440..4d9b2c5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,7 @@
ACLOCAL_AMFLAGS = -I tools/build-aux/m4
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src
+
+if BUILD_FUZZ
+SUBDIRS += fuzz
+endif
diff --git a/README.md b/README.md
index 6dd5f9e..337dfe8 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,11 @@ $ brew install swig
- `--disable-tests`. Disables building library tests. (default: no)
- `--disable-clear-tests`. Disables just the test_clear test (required to pass
the test suite with some compilers). (default: no)
+- `--enable-fuzzing`. Enables fuzzing support by compiling with
+ `-fsanitize=fuzzer-no-link` and builds fuzz targets. (default: no).
+- `--enable-address-sanitizer`. Enables the address sanitizer for detecting
+ memory errors. (default: no).
+- `--enable-ub-sanitizer`. Enables the undefined behavior sanitizer. (default: no).
### Recommended development configure options
diff --git a/_CMakeLists.txt b/_CMakeLists.txt
index 56b31ed..9333779 100644
--- a/_CMakeLists.txt
+++ b/_CMakeLists.txt
@@ -13,6 +13,23 @@ option(WALLYCORE_ENABLE_TESTS "Build tests" OFF)
option(WALLYCORE_INSTALL "Enable install" OFF)
option(WALLYCORE_COVERAGE "Enable coverage" OFF)
option(WALLYCORE_BUILD_ELEMENTS "Build elements" ON)
+option(WALLYCORE_ENABLE_FUZZING "Enable fuzzing support" OFF)
+option(WALLYCORE_ENABLE_ADDRESS_SANITIZER "Enable address sanitizer" OFF)
+option(WALLYCORE_ENABLE_UB_SANITIZER "Enable undefined behavior sanitizer" OFF)
+
+if(WALLYCORE_ENABLE_FUZZING)
+ add_compile_options(-fsanitize=fuzzer-no-link)
+endif()
+
+if(WALLYCORE_ENABLE_ADDRESS_SANITIZER)
+ add_compile_options(-fsanitize=address)
+ add_link_options(-fsanitize=address)
+endif()
+
+if(WALLYCORE_ENABLE_UB_SANITIZER)
+ add_compile_options(-fsanitize=undefined)
+ add_link_options(-fsanitize=undefined)
+endif()
include(cmake/utils.cmake)
generate_config_file()
@@ -42,6 +59,14 @@ add_subdirectory(./src/secp256k1/)
add_subdirectory(./src)
+if(WALLYCORE_ENABLE_FUZZING)
+ add_executable(fuzz_psbt fuzz/fuzz_psbt.c)
+ target_include_directories(fuzz_psbt PRIVATE include)
+ target_link_libraries(fuzz_psbt PRIVATE wallycore)
+ target_link_options(fuzz_psbt PRIVATE -fsanitize=fuzzer)
+ set_target_properties(fuzz_psbt PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/fuzz)
+endif()
+
if(NOT WALLYCORE_ENABLE_TESTS)
return()
endif()
diff --git a/configure.ac b/configure.ac
index dc66e6f..d74da95 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,7 +91,17 @@ AC_ARG_ENABLE(secp256k1-tests,
AC_ARG_ENABLE(asm,
AS_HELP_STRING([--enable-asm],[enable assembly language implementations (default: yes)]),
[asm=$enableval], [asm=yes])
+AC_ARG_ENABLE(fuzzing,
+ AS_HELP_STRING([--enable-fuzzing],[enable fuzzing support (default: no)]),
+ [fuzzing=$enableval], [fuzzing=no])
+AC_ARG_ENABLE(address-sanitizer,
+ AS_HELP_STRING([--enable-address-sanitizer],[enable address sanitizer (default: no)]),
+ [address_sanitizer=$enableval], [address_sanitizer=no])
+AC_ARG_ENABLE(ub-sanitizer,
+ AS_HELP_STRING([--enable-ub-sanitizer],[enable undefined behavior sanitizer (default: no)]),
+ [ub_sanitizer=$enableval], [ub_sanitizer=no])
AM_CONDITIONAL([RUN_TESTS], [test "x$tests" = "xyes"])
+AM_CONDITIONAL([BUILD_FUZZ], [test "x$fuzzing" = "xyes"])
AM_CONDITIONAL([BUILD_ELEMENTS], [test "x$elements" = "xyes"])
AM_CONDITIONAL([WALLY_ABI_NO_ELEMENTS], [test "x$elements_abi" = "xno"])
AM_CONDITIONAL([BUILD_STANDARD_SECP], [test "x$standard_secp" = "xyes"])
@@ -156,6 +166,20 @@ if test "x$builtin_memset" = "xno"; then
AX_CHECK_COMPILE_FLAG([-fno-builtin-memset], [AM_CFLAGS="$AM_CFLAGS -fno-builtin"])
fi
+if test "x$fuzzing" = "xyes"; then
+ AX_CHECK_COMPILE_FLAG([-fsanitize=fuzzer-no-link], [AM_CFLAGS="$AM_CFLAGS -fsanitize=fuzzer-no-link"])
+fi
+
+if test "x$address_sanitizer" = "xyes"; then
+ AX_CHECK_COMPILE_FLAG([-fsanitize=address], [AM_CFLAGS="$AM_CFLAGS -fsanitize=address"])
+ AX_CHECK_LINK_FLAG([-fsanitize=address], [LDFLAGS="$LDFLAGS -fsanitize=address"])
+fi
+
+if test "x$ub_sanitizer" = "xyes"; then
+ AX_CHECK_COMPILE_FLAG([-fsanitize=undefined], [AM_CFLAGS="$AM_CFLAGS -fsanitize=undefined"])
+ AX_CHECK_LINK_FLAG([-fsanitize=undefined], [LDFLAGS="$LDFLAGS -fsanitize=undefined"])
+fi
+
# -flax-vector-conversions is needed for our arm assembly
AX_CHECK_COMPILE_FLAG([-flax-vector-conversions], [AM_CFLAGS="$AM_CFLAGS -flax-vector-conversions"])
AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing], [NOALIAS_CFLAGS="-fno-strict-aliasing"])
@@ -420,6 +444,10 @@ AC_CONFIG_FILES([
src/wallycore.pc
])
+if test "x$fuzzing" = "xyes"; then
+ AC_CONFIG_FILES([fuzz/Makefile])
+fi
+
secp_asm="--with-asm=auto"
if test "x$asm" = "xno"; then
secp_asm="--with-asm=no"
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
new file mode 100644
index 0000000..79cab0b
--- /dev/null
+++ b/fuzz/Makefile.am
@@ -0,0 +1,6 @@
+noinst_PROGRAMS = fuzz_psbt
+
+fuzz_psbt_SOURCES = fuzz_psbt.c
+fuzz_psbt_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS)
+fuzz_psbt_LDFLAGS = -fsanitize=fuzzer
+fuzz_psbt_LDADD = $(top_builddir)/src/libwallycore.la
diff --git a/fuzz/fuzz_psbt.c b/fuzz/fuzz_psbt.c
new file mode 100644
index 0000000..517c2f6
--- /dev/null
+++ b/fuzz/fuzz_psbt.c
@@ -0,0 +1,38 @@
+#include <wally_psbt.h>
+
+static void test_psbt(const uint8_t *data, size_t size, uint32_t flags)
+{
+ struct wally_psbt *psbt = NULL;
+ int ret;
+
+ /* Test strict parsing */
+ ret = wally_psbt_from_bytes(data, size, flags, &psbt);
+ if (psbt) {
+ if (ret == WALLY_OK && flags == WALLY_PSBT_PARSE_FLAG_STRICT) {
+ /* Parsing succeeded: try to serialize it back */
+ size_t len = 0, written = 0;
+ ret = wally_psbt_get_length(psbt, 0, &len);
+ if (ret == WALLY_OK && len) {
+ unsigned char *bytes = malloc(len);
+ if (bytes) {
+ wally_psbt_to_bytes(psbt, 0, bytes, len, &written);
+ free(bytes);
+ }
+ }
+ }
+ wally_psbt_free(psbt);
+ psbt = NULL;
+ }
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ /* Test strict parsing */
+ test_psbt(data, size, WALLY_PSBT_PARSE_FLAG_STRICT);
+ /* Test loose parsing */
+ test_psbt(data, size, WALLY_PSBT_PARSE_FLAG_LOOSE);
+ /* Test default flags (no flags) */
+ test_psbt(data, size, 0);
+
+ return 0;
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.