Skip to content

Conversation

@benalleng
Copy link
Collaborator

@benalleng benalleng commented Oct 7, 2025

This adds fuzzing infrastructure for payjoin with the inclusion
of three engine options, cargo-fuzz (libfuzzer-sys), afl++, and honggfuzz. These
two were chosen as they come with seperate tradeoffs in regards to speed
and error handling.

Because these two fuzzers are setup as mutually exclusive fuzzers within
the same target file fuzzing cannot reasonably be built with
--all-features.

In addition honggfuzz and afl are seemingly broken on nix so I don't think it is reasonably
possible at this time to nixify our fuzzing crate.

The readme for reading pleasure https://github.com/benalleng/rust-payjoin/blob/fuzzing/fuzz/README.md

NB The tests that I have written are not guaranteed as good fuzzing targets and that I my hope for the mob coding session on Wednesday 1/14 next week to shore up before this is merge-able

Pull Request Checklist

Please confirm the following before requesting review:

@coveralls
Copy link
Collaborator

coveralls commented Oct 7, 2025

Pull Request Test Coverage Report for Build 21079319823

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 83.058%

Totals Coverage Status
Change from base Build 21044982881: 0.0%
Covered Lines: 9771
Relevant Lines: 11764

💛 - Coveralls

@benalleng
Copy link
Collaborator Author

Following the summit I thought it would be a good idea to try and follow the way that rust-lightning builds their fuzz infra https://github.com/lightningdevkit/rust-lightning/tree/main/fuzz with multiple fuzz suites, however I cannot get honggfuzz running on my machine for the life of me, maybe a personal nix problem but I also found this comment rust-fuzz/honggfuzz-rs#106 so I am not totally sure if there is a larger issue with hongfuzz at the moment.

@benalleng
Copy link
Collaborator Author

I excluded fuzzing from linting as the crate does not follow --all-features namely looking for a user to choose the fuzzing engine with a specific feature flag

@benalleng benalleng changed the title [WIP] Create POC for fuzzing payjoin [WIP] Introduce fuzzing for payjoin Jan 6, 2026
@benalleng benalleng force-pushed the fuzzing branch 10 times, most recently from cfcd3fe to 7cdc884 Compare January 7, 2026 20:44
@benalleng benalleng changed the title [WIP] Introduce fuzzing for payjoin Introduce fuzzing for payjoin Jan 7, 2026
@benalleng benalleng marked this pull request as ready for review January 7, 2026 20:47
@benalleng benalleng requested a review from nothingmuch January 7, 2026 20:48
@benalleng benalleng force-pushed the fuzzing branch 5 times, most recently from f7f5b33 to 8655ffd Compare January 15, 2026 15:40
@benalleng
Copy link
Collaborator Author

benalleng commented Jan 15, 2026

I have added these 2 pre-configurations to the fuzz shells as it seems easier for most people to simply skip these optimizations but if we want to have a more efficient we probably need to address these.

Your system is configured to send core dump notifications to an
    external utility. This will cause issues: there will be an extended delay
    between stumbling upon a crash and having this information relayed to the
    fuzzer via the standard waitpid() API.
    If you're just experimenting, set 'AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1'.

    To avoid having crashes misinterpreted as timeouts, please 
    temporarily modify /proc/sys/kernel/core_pattern, like so:

    echo core | sudo tee /proc/sys/kernel/core_pattern

and

Whoops, your system uses on-demand CPU frequency scaling, adjusted
    between 1075 and 5139 MHz. Unfortunately, the scaling algorithm in the
    kernel is imperfect and can miss the short-lived processes spawned by
    afl-fuzz. To keep things moving, run these commands as root:

    cd /sys/devices/system/cpu
    echo performance | sudo tee cpu*/cpufreq/scaling_governor

    You can later go back to the original state by replacing 'performance'
    with 'ondemand' or 'powersave'. If you don't want to change the settings,
    set AFL_SKIP_CPUFREQ to make afl-fuzz skip this check - but expect some
    performance drop.

[-] PROGRAM ABORT : Suboptimal CPU scaling governor
         Location : check_cpu_governor(), src/afl-fuzz-init.c:2753

Again I don't these are critical for CI fuzzing or just running the ./fuzz.sh script but I do believe that if we want say a long-running fuzzer these could result in significant performace holdups.

The docs are less helpful than I would hope https://afl-1.readthedocs.io/en/latest/user_guide.html#settings-for-afl-fuzz

If you are Jakub, you may need AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES. Others need not apply.

Edit: Maybe just a readme step telling users to follow those 2 steps as setup for afl is sufficient

Copy link
Collaborator

@nothingmuch nothingmuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these changes partially fix:

  • cargo-honggfuzz package name
  • applying the overlay instead of only re-exporting it as an output of our flake
  • adding this package to the environment
  • crate & honggfuzz version mismatch

however, bash fuzz.sh hfuzz still fails to build, due to a C compilation error:

we should probably copy fedimint's homework here

error: failed to run custom build command for `honggfuzz v0.5.58`

Caused by:
  process didn't exit successfully: `/home/user/code/github.com/payjoin/rust-payjoin/fuzz/hfuzz_target/release/build/honggfuzz-a4afbd6c254bbc3c/build-script-build` (exit status: 101)
  --- stdout
  make: Entering directory '/home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/honggfuzz-0.5.58/honggfuzz'
  rm -f -r core Makefile.bak cmdline.o display.o fuzz.o honggfuzz.o input.o mangle.o report.o sanitizers.o socketfuzzer.o subproc.o linux/arch.o linux/bfd.o linux/perf.o linux/pt.o linux/trace.o linux/unwind.o honggfuzz hfuzz_cc/hfuzz-cc libhfuzz/libhfuzz.a libhfuzz/libhfuzz.so libhfuzz/fetch.o libhfuzz/instrument.o libhfuzz/linux.o libhfuzz/memorycmp.o libhfuzz/performance.o libhfuzz/persistent.o libhfcommon/libhfcommon.a libhfcommon/files.o libhfcommon/log.o libhfcommon/ns.o libhfcommon/util.o libhfnetdriver/libhfnetdriver.a libhfnetdriver/netdriver.o  obj libs ./*.o ./*~ ./core ./*.a ./*.dSYM ./*.la ./*.so ./*.dylib linux/*.o linux/*~ linux/core linux/*.a linux/*.dSYM linux/*.la linux/*.so linux/*.dylib mac/*.o mac/*~ mac/core mac/*.a mac/*.dSYM mac/*.la mac/*.so mac/*.dylib netbsd/*.o netbsd/*~ netbsd/core netbsd/*.a netbsd/*.dSYM netbsd/*.la netbsd/*.so netbsd/*.dylib posix/*.o posix/*~ posix/core posix/*.a posix/*.dSYM posix/*.la posix/*.so posix/*.dylib libhfuzz/*.o libhfuzz/*~ libhfuzz/core libhfuzz/*.a libhfuzz/*.dSYM libhfuzz/*.la libhfuzz/*.so libhfuzz/*.dylib libhfcommon/*.o libhfcommon/*~ libhfcommon/core libhfcommon/*.a libhfcommon/*.dSYM libhfcommon/*.la libhfcommon/*.so libhfcommon/*.dylib libhfnetdriver/*.o libhfnetdriver/*~ libhfnetdriver/core libhfnetdriver/*.a libhfnetdriver/*.dSYM libhfnetdriver/*.la libhfnetdriver/*.so libhfnetdriver/*.dylib
  make: Leaving directory '/home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/honggfuzz-0.5.58/honggfuzz'
  make: Entering directory '/home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/honggfuzz-0.5.58/honggfuzz'
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o cmdline.o cmdline.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o display.o display.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o fuzz.o fuzz.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o honggfuzz.o honggfuzz.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o input.o input.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o mangle.o mangle.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o report.o report.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o sanitizers.o sanitizers.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o socketfuzzer.o socketfuzzer.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o subproc.o subproc.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o linux/arch.o linux/arch.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o linux/bfd.o linux/bfd.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o linux/perf.o linux/perf.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o linux/pt.o linux/pt.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o linux/trace.o linux/trace.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3  -o linux/unwind.o linux/unwind.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfcommon/files.o libhfcommon/files.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfcommon/log.o libhfcommon/log.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfcommon/ns.o libhfcommon/ns.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfcommon/util.o libhfcommon/util.c
  ar rcs libhfcommon/libhfcommon.a libhfcommon/files.o libhfcommon/log.o libhfcommon/ns.o libhfcommon/util.o
  gcc -o honggfuzz cmdline.o display.o fuzz.o honggfuzz.o input.o mangle.o report.o sanitizers.o socketfuzzer.o subproc.o linux/arch.o linux/bfd.o linux/perf.o linux/pt.o linux/trace.o linux/unwind.o libhfcommon/libhfcommon.a -pthread -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lm -L/usr/local/include -lunwind-ptrace -lunwind-generic -lunwind  -llzma -lopcodes -lbfd -lrt -ldl -lm -latomic -g -ggdb -g3
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfuzz/fetch.o libhfuzz/fetch.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfuzz/instrument.o libhfuzz/instrument.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfuzz/linux.o libhfuzz/linux.c
  gcc -c -O3 -mtune=native -funroll-loops -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -D_FILE_OFFSET_BITS=64 -finline-limit=4000 -D_HF_ARCH_LINUX -D_HF_ARCH_LINUX -g -ggdb -g3 -fPIC -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0   -o libhfuzz/memorycmp.o libhfuzz/memorycmp.c
  make: Leaving directory '/home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/honggfuzz-0.5.58/honggfuzz'

  --- stderr

... ellided someredundant warnings

  warning: Skipping impure flag -mtune=native because NIX_ENFORCE_NO_NATIVE is set
  In file included from /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/features.h:511,
                   from /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/ctype.h:25,
                   from libhfuzz/memorycmp.c:1:
  /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/bits/string_fortified.h:77:1: error: 'strcpy' defined both normally and as 'alias' attribute
     77 | __NTH (strcpy (__fortify_clang_overload_arg (char *, __restrict, __dest),
        | ^~~~~
  /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/bits/string_fortified.h:136:1: error: 'strcat' defined both normally and as 'alias' attribute
    136 | __NTH (strcat (__fortify_clang_overload_arg (char *, __restrict, __dest),
        | ^~~~~
  /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/bits/string_fortified.h:161:1: error: 'strlcpy' defined both normally and as 'alias' attribute
    161 | __NTH (strlcpy (__fortify_clang_overload_arg (char *, __restrict, __dest),
        | ^~~~~
  /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/bits/string_fortified.h:179:1: error: 'strlcat' defined both normally and as 'alias' attribute
    179 | __NTH (strlcat (__fortify_clang_overload_arg (char *, __restrict, __dest),
        | ^~~~~
  make: *** [Makefile:311: libhfuzz/memorycmp.o] Error 1

  thread 'main' (1564888) panicked at /home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/honggfuzz-0.5.58/build.rs:63:5:
  assertion failed: status.success()
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...

@spacebear21
Copy link
Collaborator

I should've asked this on yesterday's call but time ran out and I needed to hop off. Are there other areas of the codebase that you have in mind for fuzz testing candidates in follow-ups? PSBT and uri parsing are nice as an introduction for fuzzing but aren't directly payjoin related. Maybe the payjoin directory/service since it might accept arbitrary inputs from the Internet? It would be nice to document and track fuzz candidates in an issue.

@benalleng benalleng mentioned this pull request Jan 16, 2026
5 tasks
@benalleng benalleng force-pushed the fuzzing branch 4 times, most recently from 00266e7 to f4cc3c1 Compare January 16, 2026 18:10
benalleng and others added 3 commits January 16, 2026 14:39
This commit adds fuzzing infrastructure for payjoin with the inclusion
of three engine options, cargo-fuzz (libfuzzer-sys), afl++, and honggfuzz.  These
two were chosen as they come with seperate tradeoffs in regards to speed
and error handling.

Because these two fuzzers are setup as mutually exclusive fuzzers within
the same target file fuzzing cannot reasonably be built with
`--all-features`.

In addition honggfuzz and afl are seemingly broken on nix so I don't think it is reasonably
possible at this time to nixify our fuzzing crate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants