Some checks are pending
Fuzz Smoke / libFuzzer smoke (push) Waiting to run
Startup ordering defects were only observable by waiting minutes on a live daemon, and the one that aborted it took a live restart loop to find. Give the startup contracts a deterministic harness that runs in milliseconds. + startup_fuzz_support.h drives the real ServiceManagerFsm and the real DeferralGate with virtual time: legal phase advances, injected failure, shutdown and terminal reset, idle/busy, pressure/calm, starvation deadlines and cancellation + oracles fail closed on shutdown resurrection without reset, failure-to-ready, eligibility disagreeing with fsm.isReady(), admission outside the virtual deadline, and ineligible work touching the admission gate; fuzzed IEEE-754 components must never yield non-finite or out-of-range scores + catch2_startup_replay runs named regressions plus 1024 seeded traces per run and reports the root seed and action offset for replay + fuzz_startup builds the same harness for libFuzzer/AFL, with a seed generator that refuses to overwrite different existing files - the fuzzing lane no longer defaults to TSan: harnesses link -fsanitize=fuzzer,address,undefined and the two runtimes cannot share a process; combining them now fails with an explanation instead of producing a binary that cannot start - documented the lane invocation, target naming and the coverage limits, including that governor call ordering inside the poller is not covered Scope: contract-valid single-owner schedules. Executor interleavings, late callbacks, concurrent FSM instances and filesystem/model faults are not modeled. Signed-off-by: trvon <git@trevon.dev>
301 lines
10 KiB
Meson
301 lines
10 KiB
Meson
# YAMS Fuzzing Harnesses
|
|
#
|
|
# Two engines share these targets (selected in the top-level meson.build):
|
|
# afl - AFL++ in libFuzzer compatibility mode (afl-clang-fast++, Docker):
|
|
# ./tools/fuzzing/fuzz.sh build
|
|
# libfuzzer - plain clang with the libFuzzer runtime; every project object is built with
|
|
# -fsanitize=fuzzer-no-link plus ASan/UBSan, harnesses link -fsanitize=fuzzer:
|
|
# CC=clang CXX=clang++ meson setup build/fuzzing -Dbuild-fuzzers=true -Db_lundef=false \
|
|
# -Dbuild-tests=false -Dbuild-plugins=false -Dbuild-cli=false
|
|
# meson compile -C build/fuzzing tools/fuzzing/fuzz_startup
|
|
# then ./tools/fuzzing/fuzz.sh local <target> (see fuzz.sh usage).
|
|
|
|
cpp = meson.get_compiler('cpp')
|
|
|
|
if yams_fuzz_engine == 'none'
|
|
warning('No fuzzing engine detected. Use afl-clang-fast++ (./tools/fuzzing/fuzz.sh build) '
|
|
+ 'or a clang that ships the libFuzzer runtime (e.g. Homebrew/apt LLVM).')
|
|
subdir_done()
|
|
endif
|
|
|
|
message('Fuzzing engine ' + yams_fuzz_engine + ' detected - building fuzzers')
|
|
|
|
# Fuzzers include Boost.Asio headers directly; ensure Boost include/link flags
|
|
# are present when compiling the harnesses (static libraries don't propagate
|
|
# include dirs to consumers).
|
|
fuzz_deps = [
|
|
boost_dep,
|
|
dependency('threads'),
|
|
dependency('zlib'),
|
|
dependency('OpenSSL'),
|
|
dependency('protobuf'),
|
|
dependency('nlohmann_json'),
|
|
]
|
|
if host_machine.system() == 'windows'
|
|
fuzz_deps += cpp.find_library('advapi32', required: true)
|
|
endif
|
|
|
|
# Seed generator (non-fuzzer utility)
|
|
seedgen = executable('seedgen',
|
|
'seedgen.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# AFL++ libFuzzer compatibility mode flags
|
|
# Per docs: "-fsanitize=fuzzer" provides automatic persistent mode. AFL applies ASan through
|
|
# AFL_USE_ASAN; plain libFuzzer builds link the sanitizer runtimes explicitly.
|
|
if yams_fuzz_engine == 'afl'
|
|
fuzzer_args = ['-fsanitize=fuzzer']
|
|
else
|
|
fuzzer_args = ['-fsanitize=fuzzer,address,undefined']
|
|
endif
|
|
|
|
# Controlled ABI plugin used by fuzz_plugin_abi_mount.
|
|
# This keeps dlopen() deterministic and avoids loading random fuzz bytes as shared libs.
|
|
fuzz_abi_test_plugin = shared_module('fuzz_abi_test_plugin',
|
|
'fuzz_abi_test_plugin.c',
|
|
include_directories: include_directories('../../include'),
|
|
c_args: ['-fPIC'],
|
|
install: false,
|
|
build_by_default: true,
|
|
)
|
|
|
|
fuzz_abi_negotiation_plugin = shared_module('fuzz_abi_negotiation_plugin',
|
|
'fuzz_abi_negotiation_plugin.c',
|
|
include_directories: include_directories('../../include'),
|
|
c_args: ['-fPIC'],
|
|
install: false,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Link against the daemon library built in this tree
|
|
# The daemon library contains MessageFramer and IPC protocol implementation
|
|
# Note: yams_daemon_lib is defined in src/daemon/meson.build and available in this scope
|
|
|
|
# Startup lifecycle/pressure schedules and semantic-score boundary. Shared replay support
|
|
# also runs under Catch2; this target adds the configured coverage-guided fuzzing engine.
|
|
fuzz_startup = executable('fuzz_startup',
|
|
'fuzz_startup.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
# The harness includes spdlog directly; link_with does not propagate that dependency's
|
|
# include paths or compile definitions (same reason as fuzz_deps above).
|
|
dependencies: fuzz_deps + [dependency('spdlog')],
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# IPC Protocol Fuzzer
|
|
fuzz_ipc_protocol = executable('fuzz_ipc_protocol',
|
|
'fuzz_ipc_protocol.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Direct P2P protocol-v4 handshake/control fuzzer.
|
|
# The corpus retains protocol-v3 seeds to continuously exercise exact-version rejection.
|
|
fuzz_p2p_protocol = executable('fuzz_p2p_protocol',
|
|
'fuzz_p2p_protocol.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Direct P2P delta/bootstrap control-message fuzzer.
|
|
fuzz_p2p_delta = executable('fuzz_p2p_delta',
|
|
'fuzz_p2p_delta.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Direct P2P lane over the FrameSource seam: frame JSON, connection strings and pins, the
|
|
# handshake validators and acceptor, the delta receive paths with fuzzed session bounds, and the
|
|
# full manager inbound session. Each harness traps on an oracle violation.
|
|
foreach p2p_target : ['p2p_json', 'p2p_connstr', 'p2p_handshake', 'p2p_delta_stream',
|
|
'p2p_inbound']
|
|
executable('fuzz_' + p2p_target,
|
|
'fuzz_' + p2p_target + '.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
endforeach
|
|
|
|
# Topology snapshot decoder (untrusted persisted payloads).
|
|
fuzz_topology_codec = executable('fuzz_topology_codec',
|
|
'fuzz_topology_codec.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps + [dependency('yams_topology')],
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# FTS5 user-query sanitizer (MCP / CLI search text) against a real FTS5 table
|
|
fuzz_fts5_query = executable('fuzz_fts5_query',
|
|
'fuzz_fts5_query.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps + [sqlite_dep],
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# UTF-8 sanitizers + encoding detection/conversion on ingested bytes
|
|
fuzz_utf8 = executable('fuzz_utf8',
|
|
'fuzz_utf8.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# HTML / plain-text extractors, title and section detection on ingested bytes
|
|
fuzz_text_extractors = executable('fuzz_text_extractors',
|
|
'fuzz_text_extractors.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Stored compressed blocks (header + zstd/LZMA payload) and compressor round-trips
|
|
fuzz_compressed_block = executable('fuzz_compressed_block',
|
|
'fuzz_compressed_block.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# AddDocumentRequest Fuzzer
|
|
fuzz_add_document = executable('fuzz_add_document',
|
|
'fuzz_add_document.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# ProtoSerializer Fuzzer
|
|
fuzz_proto_serializer = executable('fuzz_proto_serializer',
|
|
'fuzz_proto_serializer.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# RequestHandler Fuzzer
|
|
fuzz_request_handler = executable('fuzz_request_handler',
|
|
'fuzz_request_handler.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# StreamingRequestProcessor Fuzzer
|
|
fuzz_streaming_processor = executable('fuzz_streaming_processor',
|
|
'fuzz_streaming_processor.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# IPC Roundtrip Fuzzer (CLI<->daemon framing + payload)
|
|
fuzz_ipc_roundtrip = executable('fuzz_ipc_roundtrip',
|
|
'fuzz_ipc_roundtrip.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Plugin Trust/Path Fuzzer (trust file parsing + safe path containment)
|
|
fuzz_plugin_trust = executable('fuzz_plugin_trust',
|
|
'fuzz_plugin_trust.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# ABI plugin mount fuzzer (loads controlled test plugin .so through AbiPluginLoader)
|
|
fuzz_plugin_abi_mount = executable('fuzz_plugin_abi_mount',
|
|
'fuzz_plugin_abi_mount.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# ABI interface/manifest negotiation fuzzer
|
|
fuzz_plugin_abi_negotiation = executable('fuzz_plugin_abi_negotiation',
|
|
'fuzz_plugin_abi_negotiation.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
# Daemon download job IPC fuzzer
|
|
fuzz_download_jobs = executable('fuzz_download_jobs',
|
|
'fuzz_download_jobs.cpp',
|
|
include_directories: include_directories('../../include'),
|
|
link_with: yams_daemon_lib,
|
|
dependencies: fuzz_deps,
|
|
cpp_args: fuzzer_args,
|
|
link_args: fuzzer_args,
|
|
build_by_default: true,
|
|
)
|
|
|
|
if yams_fuzz_engine == 'afl'
|
|
message('Fuzzing harnesses configured with AFL++ libFuzzer mode')
|
|
message('ASAN enabled via AFL_USE_ASAN=1 environment variable')
|
|
else
|
|
message('Fuzzing harnesses configured with libFuzzer + ASan/UBSan')
|
|
endif
|