/src/curl_fuzzer/proto_fuzzer/fuzzer_main.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al. |
3 | | * |
4 | | * SPDX-License-Identifier: curl |
5 | | */ |
6 | | |
7 | | /// @file |
8 | | /// @brief Shared libFuzzer entrypoint for the policy-split protobuf targets. |
9 | | /// Wires each binary's LPM policy to ScenarioRunner::Run. |
10 | | |
11 | | #include <curl/curl.h> |
12 | | #include <libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h> |
13 | | |
14 | | #include <csignal> |
15 | | |
16 | | #include "curl_fuzzer.pb.h" |
17 | | #include "proto_fuzzer/option_apply.h" |
18 | | #include "proto_fuzzer/scenario_runner.h" |
19 | | #include "proto_fuzzer/target_policy.h" |
20 | | |
21 | | namespace { |
22 | | |
23 | | #if defined(PROTO_FUZZER_TARGET_COMPATIBILITY) |
24 | | // The original target deliberately has no policy. Its OSS-Fuzz corpus and |
25 | | // regression testcases contain mixed schemes and timing controls whose exact |
26 | | // semantics must remain stable across the target split. |
27 | | #elif defined(PROTO_FUZZER_TARGET_FAST_HTTP) |
28 | | constexpr proto_fuzzer::TargetPolicy kTargetPolicy = proto_fuzzer::TargetPolicy::kFastHttp; |
29 | | #elif defined(PROTO_FUZZER_TARGET_DEEP_HTTP) |
30 | | constexpr proto_fuzzer::TargetPolicy kTargetPolicy = proto_fuzzer::TargetPolicy::kDeepHttp; |
31 | | #elif defined(PROTO_FUZZER_TARGET_FAST_HTTPS) |
32 | | constexpr proto_fuzzer::TargetPolicy kTargetPolicy = proto_fuzzer::TargetPolicy::kFastHttps; |
33 | | #elif defined(PROTO_FUZZER_TARGET_FAST_WEBSOCKET) |
34 | | constexpr proto_fuzzer::TargetPolicy kTargetPolicy = proto_fuzzer::TargetPolicy::kFastWebSocket; |
35 | | #elif defined(PROTO_FUZZER_TARGET_FAST_SECURE_WEBSOCKET) |
36 | | constexpr proto_fuzzer::TargetPolicy kTargetPolicy = proto_fuzzer::TargetPolicy::kFastSecureWebSocket; |
37 | | #elif defined(PROTO_FUZZER_TARGET_TIMING) |
38 | | constexpr proto_fuzzer::TargetPolicy kTargetPolicy = proto_fuzzer::TargetPolicy::kTiming; |
39 | | #else |
40 | | #error "A proto fuzzer target policy must be selected" |
41 | | #endif |
42 | | |
43 | | // The fast HTTP binary trades the post-transfer getinfo/header probes for |
44 | | // throughput. Every other compiled lane retains them, so the aggregate proto |
45 | | // suite still covers those APIs without charging the hottest mutation loop. |
46 | | #if defined(PROTO_FUZZER_TARGET_FAST_HTTP) |
47 | | constexpr bool kProbeTransferResults = false; |
48 | | #else |
49 | | constexpr bool kProbeTransferResults = true; |
50 | | #endif |
51 | | |
52 | | #if !defined(PROTO_FUZZER_TARGET_COMPATIBILITY) |
53 | | /// Restore the target's protocol and timing invariants after every mutation. |
54 | | /// Registering this during static initialization matters: corpus inputs pass |
55 | | /// through LPM's Fix() before the first fuzz callback, so a function-local |
56 | | /// registration would let the first input bypass the target policy. |
57 | 0 | void PostProcessScenario(curl::fuzzer::proto::Scenario* scenario, unsigned int /*seed*/) { |
58 | 0 | proto_fuzzer::ApplyTargetPolicy(scenario, kTargetPolicy); |
59 | 0 | proto_fuzzer::CanonicalizeOptionValueCases(scenario); |
60 | 0 | } |
61 | | |
62 | | const protobuf_mutator::libfuzzer::PostProcessorRegistration<curl::fuzzer::proto::Scenario> kPolicyRegistration( |
63 | | &PostProcessScenario); |
64 | | #endif |
65 | | |
66 | | // Wire curl_global_init once so repeated fuzz iterations don't pay for it on every call. libFuzzer reuses the process; |
67 | | // static ctors run once. |
68 | | struct CurlGlobalBootstrap { |
69 | 8 | CurlGlobalBootstrap() { |
70 | | // Keep parity with the legacy harness. libcurl normally suppresses |
71 | | // SIGPIPE for its own writes, but fuzzed connection lifecycles also race |
72 | | // mock-peer teardown; those failures should be reported as socket errors, |
73 | | // not mistaken for process crashes. |
74 | 8 | std::signal(SIGPIPE, SIG_IGN); |
75 | 8 | curl_global_init(CURL_GLOBAL_ALL); |
76 | 8 | } |
77 | | }; |
78 | | const CurlGlobalBootstrap kGlobalBootstrap; |
79 | | |
80 | | } // namespace |
81 | | |
82 | | /// @brief libFuzzer entry point. libFuzzer will call this function with a valid Scenario protobuf message on each |
83 | | /// fuzzing iteration. The function is expected to run the scenario and return. Any crashes or undefined behavior during |
84 | | /// scenario execution will be reported by libFuzzer as fuzzing bugs. |
85 | | /// @param scenario The Scenario describing the curl operations to perform. |
86 | 10.1k | DEFINE_BINARY_PROTO_FUZZER(const curl::fuzzer::proto::Scenario& scenario) { |
87 | 10.1k | proto_fuzzer::ScenarioRunner().Run(scenario, kProbeTransferResults); |
88 | 10.1k | } |