OxL Справочник OxL
РусскийEnglish

Fuzzing (TZ 3.5 / 5.2)

libFuzzer harnesses for the code that parses bytes we do not control live in tests/fuzz/. They run with ASan + UBSan + LeakSanitizer.

TargetWhat is fuzzedProperties checked
fuzz_serstd.ser decoders (runtime/src/ser_bin.cpp, ser_json.cpp, ser_doc.cpp): protobuf wire format, canonical JSON, MessagePack and CBOR ([С §9.3]) against a hand-built schema covering all node kinds (scalars, str/bytes, enum, oneof, optional, list, map, set, array, nested message, Duration/Timestamp/Date); byte 0 = root << 2 | format (0 binary, 1 JSON, 2 MessagePack, 3 CBOR)no crash/UB/leak; decode -> encode -> decode -> encode is canonical
fuzz_grpc_wiregRPC helpers parsing peer data (runtime/src/grpc/wire.cpp): grpc-timeout, grpc-status-details-bin, base64, percent-decoding, metadata validation, framinground-trips
fuzz_h2a real HTTP/2 server connection (our nghttp2 glue, runtime/src/http2) plus gRPC message framing (readMessage) fed with hostile frames over a socketpair on the OxL schedulerno crash/UB/leak/hang; every handler task ends with its connection
fuzz_http1HTTP/1.1 client response parser (runtime/src/http1/http1.cpp: status line, headers, chunked / length / close-delimited bodies, redirects) against a hostile loopback server thread, through the oxl_http_* C ABIno crash/UB/leak/hang
fuzz_jwtthe authentication parsers (runtime/oxlsec: strict JSON, JWKS documents, compact JWTs against a generated Ed25519 key set, join tokens, signed deny-lists, principals); byte 0 selects the targetno crash/UB/leak/hang; a token is accepted only when it is the one valid token the harness signed (no forged or bit-flipped token ever verifies)
fuzz_configstatic configuration: TOML subset parser, duration/size texts, and the loader driven with fuzzed flags / environment / config/<profile>.tomlno crash/UB/leak
fuzz_frontendOxL lexer, parser and oxl fmtno crash/UB; the formatter's AST-equivalence + idempotency check never falls back

Running#

sh
scripts/fuzz.sh                       # all targets, 300 s each, build-fuzz/
scripts/fuzz.sh --time 1800 fuzz_ser  # one target for 30 minutes
scripts/fuzz.sh --jobs 2 fuzz_h2      # libFuzzer fork mode with 2 workers

scripts/fuzz.sh configures build-fuzz/ with -DOXL_SANITIZE=address,undefined -DOXL_FUZZ=ON and builds only the fuzz targets. The working corpus is build-fuzz/corpus/<target>/ (seeded from tests/fuzz/corpus/<target>/, kept between runs); crashes land in build-fuzz/artifacts/. OXL_FUZZ=ON builds the whole tree with -fsanitize=fuzzer-no-link, so the runtime is coverage-instrumented; it requires OXL_SANITIZE.

Smoke test in ctest. With OXL_FUZZ=ON every target also registers fuzz_*_smoke (label fuzz): tests/fuzz/smoke.sh replays the seed corpus and fuzzes for OXL_FUZZ_SMOKE_SECONDS (default 3) in a scratch copy (the checked-in seeds are not modified). In a normal build these tests do not exist.

sh
cmake -S . -B build-fuzz -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DOXL_SANITIZE=address,undefined -DOXL_FUZZ=ON
ninja -C build-fuzz && ctest --test-dir build-fuzz -L fuzz

When a fuzzer finds a crash#

  1. Reproduce: build-fuzz/tests/fuzz/fuzz_ser build-fuzz/artifacts/fuzz_ser-crash-...; minimise with -minimize_crash=1.
  2. Fix the bug in runtime/ or compiler/.
  3. Add a regression test with the input embedded to tests/unit/runtime/fuzz_regress_test.cpp (or next to the component's tests), and, if the input exercises new paths, copy it to tests/fuzz/corpus/<target>/.

Findings#

See "Bugs found and fixed" in docs/sanitizers.md; fuzzers found the parseRfc3339 signed overflow (fuzz_ser). The seed corpus is hand-written (tests/fuzz/corpus/); the schema of fuzz_ser and the framing in fuzz_h2 are documented in the harness sources.

Not covered#

TLS record layer (OpenSSL), PostgreSQL wire protocol client, and the oxl driver's manifest/lock-file readers have no harness yet.

Исходник: docs/fuzzing.md

OxL 1.0.0-beta · Версия документации 1.0.0-beta© OxwaldLink · сгенерировано из Стандарта, исходников std и руководства