xref: /aosp_15_r20/external/cronet/net/quic/quic_session_pool_fuzzer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/quic/quic_session_pool.h"
6 
7 #include <fuzzer/FuzzedDataProvider.h>
8 
9 #include <algorithm>
10 
11 #include "base/no_destructor.h"
12 #include "base/task/sequenced_task_runner.h"
13 #include "net/base/network_anonymization_key.h"
14 #include "net/base/privacy_mode.h"
15 #include "net/base/proxy_chain.h"
16 #include "net/base/session_usage.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/cert/do_nothing_ct_verifier.h"
19 #include "net/cert/mock_cert_verifier.h"
20 #include "net/cert/x509_certificate.h"
21 #include "net/dns/context_host_resolver.h"
22 #include "net/dns/fuzzed_host_resolver_util.h"
23 #include "net/dns/host_resolver_system_task.h"
24 #include "net/dns/public/secure_dns_policy.h"
25 #include "net/http/http_server_properties.h"
26 #include "net/http/transport_security_state.h"
27 #include "net/quic/mock_crypto_client_stream_factory.h"
28 #include "net/quic/mock_quic_context.h"
29 #include "net/quic/quic_context.h"
30 #include "net/quic/quic_http_stream.h"
31 #include "net/quic/quic_session_key.h"
32 #include "net/quic/test_task_runner.h"
33 #include "net/socket/fuzzed_datagram_client_socket.h"
34 #include "net/socket/fuzzed_socket_factory.h"
35 #include "net/socket/socket_tag.h"
36 #include "net/ssl/ssl_config_service_defaults.h"
37 #include "net/test/gtest_util.h"
38 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
39 #include "url/scheme_host_port.h"
40 #include "url/url_constants.h"
41 
42 namespace net {
43 
44 namespace {
45 
46 const uint8_t kCertData[] = {
47 #include "net/data/ssl/certificates/wildcard.inc"
48 };
49 
50 }  // namespace
51 
52 namespace test {
53 
54 const char kServerHostName[] = "www.example.org";
55 const int kServerPort = 443;
56 const char kUrl[] = "https://www.example.org/";
57 // TODO(nedwilliamson): Add POST here after testing
58 // whether that can lead blocking while waiting for
59 // the callbacks.
60 const char kMethod[] = "GET";
61 const size_t kBufferSize = 4096;
62 const int kCertVerifyFlags = 0;
63 
64 // Persistent factory data, statically initialized on the first time
65 // LLVMFuzzerTestOneInput is called.
66 struct FuzzerEnvironment {
FuzzerEnvironmentnet::test::FuzzerEnvironment67   FuzzerEnvironment()
68       : scheme_host_port(url::kHttpsScheme, kServerHostName, kServerPort) {
69     net::SetSystemDnsResolutionTaskRunnerForTesting(  // IN-TEST
70         base::SequencedTaskRunner::GetCurrentDefault());
71 
72     quic_context.AdvanceTime(quic::QuicTime::Delta::FromSeconds(1));
73     ssl_config_service = std::make_unique<SSLConfigServiceDefaults>();
74     crypto_client_stream_factory.set_use_mock_crypter(true);
75     cert_verifier = std::make_unique<MockCertVerifier>();
76     verify_details.cert_verify_result.verified_cert =
77         X509Certificate::CreateFromBytes(kCertData);
78     CHECK(verify_details.cert_verify_result.verified_cert);
79     verify_details.cert_verify_result.is_issued_by_known_root = true;
80   }
81   ~FuzzerEnvironment() = default;
82 
83   std::unique_ptr<SSLConfigService> ssl_config_service;
84   ProofVerifyDetailsChromium verify_details;
85   MockCryptoClientStreamFactory crypto_client_stream_factory;
86   url::SchemeHostPort scheme_host_port;
87   NetLogWithSource net_log;
88   std::unique_ptr<CertVerifier> cert_verifier;
89   TransportSecurityState transport_security_state;
90   quic::QuicTagVector connection_options;
91   quic::QuicTagVector client_connection_options;
92   MockQuicContext quic_context;
93 };
94 
GetFuzzerEnvironment()95 FuzzerEnvironment* GetFuzzerEnvironment() {
96   static base::NoDestructor<FuzzerEnvironment> fuzzer_environment;
97   return &*fuzzer_environment;
98 }
99 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)100 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
101   FuzzedDataProvider data_provider(data, size);
102 
103   FuzzerEnvironment* env = GetFuzzerEnvironment();
104 
105   std::unique_ptr<ContextHostResolver> host_resolver =
106       CreateFuzzedContextHostResolver(HostResolver::ManagerOptions(), nullptr,
107                                       &data_provider,
108                                       true /* enable_caching */);
109   FuzzedSocketFactory socket_factory(&data_provider);
110 
111   // Initialize this on each loop since some options mutate this.
112   HttpServerProperties http_server_properties;
113 
114   QuicParams& params = *env->quic_context.params();
115   params.max_server_configs_stored_in_properties =
116       data_provider.ConsumeBool() ? 1 : 0;
117   params.close_sessions_on_ip_change = data_provider.ConsumeBool();
118   params.allow_server_migration = data_provider.ConsumeBool();
119   params.estimate_initial_rtt = data_provider.ConsumeBool();
120   params.enable_socket_recv_optimization = data_provider.ConsumeBool();
121 
122   env->crypto_client_stream_factory.AddProofVerifyDetails(&env->verify_details);
123 
124   params.goaway_sessions_on_ip_change = false;
125   params.migrate_sessions_early_v2 = false;
126   params.migrate_sessions_on_network_change_v2 = false;
127   params.retry_on_alternate_network_before_handshake = false;
128   params.migrate_idle_sessions = false;
129 
130   if (!params.close_sessions_on_ip_change) {
131     params.goaway_sessions_on_ip_change = data_provider.ConsumeBool();
132     if (!params.goaway_sessions_on_ip_change) {
133       params.migrate_sessions_on_network_change_v2 =
134           data_provider.ConsumeBool();
135       if (params.migrate_sessions_on_network_change_v2) {
136         params.migrate_sessions_early_v2 = data_provider.ConsumeBool();
137         params.retry_on_alternate_network_before_handshake =
138             data_provider.ConsumeBool();
139         params.migrate_idle_sessions = data_provider.ConsumeBool();
140       }
141     }
142   }
143 
144   std::unique_ptr<QuicSessionPool> factory = std::make_unique<QuicSessionPool>(
145       env->net_log.net_log(), host_resolver.get(),
146       env->ssl_config_service.get(), &socket_factory, &http_server_properties,
147       env->cert_verifier.get(), &env->transport_security_state, nullptr,
148       nullptr, nullptr, &env->crypto_client_stream_factory, &env->quic_context);
149 
150   QuicSessionRequest request(factory.get());
151   TestCompletionCallback callback;
152   NetErrorDetails net_error_details;
153   quic::ParsedQuicVersionVector versions = AllSupportedQuicVersions();
154   quic::ParsedQuicVersion version =
155       versions[data_provider.ConsumeIntegralInRange<size_t>(
156           0, versions.size() - 1)];
157 
158   quic::QuicEnableVersion(version);
159 
160   request.Request(
161       env->scheme_host_port, version, ProxyChain::Direct(),
162       TRAFFIC_ANNOTATION_FOR_TESTS, /*http_user_agent_settings=*/nullptr,
163       SessionUsage::kDestination, PRIVACY_MODE_DISABLED, DEFAULT_PRIORITY,
164       SocketTag(), NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
165       /*require_dns_https_alpn=*/false, kCertVerifyFlags, GURL(kUrl),
166       env->net_log, &net_error_details,
167       /*failed_on_default_network_callback=*/CompletionOnceCallback(),
168       callback.callback());
169 
170   callback.WaitForResult();
171   std::unique_ptr<QuicChromiumClientSession::Handle> session =
172       request.ReleaseSessionHandle();
173   if (!session) {
174     return 0;
175   }
176   auto dns_aliases = session->GetDnsAliasesForSessionKey(request.session_key());
177   auto stream = std::make_unique<QuicHttpStream>(std::move(session),
178                                                  std::move(dns_aliases));
179 
180   HttpRequestInfo request_info;
181   request_info.method = kMethod;
182   request_info.url = GURL(kUrl);
183   request_info.traffic_annotation =
184       MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
185   stream->RegisterRequest(&request_info);
186   stream->InitializeStream(true, DEFAULT_PRIORITY, env->net_log,
187                            CompletionOnceCallback());
188 
189   HttpResponseInfo response;
190   HttpRequestHeaders request_headers;
191   if (OK !=
192       stream->SendRequest(request_headers, &response, callback.callback())) {
193     return 0;
194   }
195 
196   // TODO(nedwilliamson): attempt connection migration here
197   int rv = stream->ReadResponseHeaders(callback.callback());
198   if (rv != OK && rv != ERR_IO_PENDING) {
199     return 0;
200   }
201   callback.WaitForResult();
202 
203   auto buffer = base::MakeRefCounted<net::IOBufferWithSize>(kBufferSize);
204   rv = stream->ReadResponseBody(buffer.get(), kBufferSize, callback.callback());
205   if (rv == ERR_IO_PENDING) {
206     callback.WaitForResult();
207   }
208 
209   return 0;
210 }
211 
212 }  // namespace test
213 }  // namespace net
214