| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/quic/quic_stream_factory.h" |
| |
| #include <fuzzer/FuzzedDataProvider.h> |
| |
| #include "base/cxx17_backports.h" |
| #include "base/no_destructor.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "net/base/network_anonymization_key.h" |
| #include "net/base/test_completion_callback.h" |
| #include "net/cert/ct_policy_enforcer.h" |
| #include "net/cert/do_nothing_ct_verifier.h" |
| #include "net/cert/mock_cert_verifier.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/dns/context_host_resolver.h" |
| #include "net/dns/fuzzed_host_resolver_util.h" |
| #include "net/dns/host_resolver_system_task.h" |
| #include "net/dns/public/secure_dns_policy.h" |
| #include "net/http/http_server_properties.h" |
| #include "net/http/transport_security_state.h" |
| #include "net/quic/mock_crypto_client_stream_factory.h" |
| #include "net/quic/mock_quic_context.h" |
| #include "net/quic/quic_context.h" |
| #include "net/quic/quic_http_stream.h" |
| #include "net/quic/test_task_runner.h" |
| #include "net/socket/fuzzed_datagram_client_socket.h" |
| #include "net/socket/fuzzed_socket_factory.h" |
| #include "net/socket/socket_tag.h" |
| #include "net/ssl/ssl_config_service_defaults.h" |
| #include "net/test/gtest_util.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "url/scheme_host_port.h" |
| #include "url/url_constants.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| const uint8_t kCertData[] = { |
| #include "net/data/ssl/certificates/wildcard.inc" |
| }; |
| |
| } // namespace |
| |
| namespace test { |
| |
| const char kServerHostName[] = "www.example.org"; |
| const int kServerPort = 443; |
| const char kUrl[] = "https://www.example.org/"; |
| // TODO(nedwilliamson): Add POST here after testing |
| // whether that can lead blocking while waiting for |
| // the callbacks. |
| const char kMethod[] = "GET"; |
| const size_t kBufferSize = 4096; |
| const int kCertVerifyFlags = 0; |
| |
| // Persistent factory data, statically initialized on the first time |
| // LLVMFuzzerTestOneInput is called. |
| struct FuzzerEnvironment { |
| FuzzerEnvironment() |
| : scheme_host_port(url::kHttpsScheme, kServerHostName, kServerPort) { |
| net::SetSystemDnsResolutionTaskRunnerForTesting( // IN-TEST |
| base::SequencedTaskRunner::GetCurrentDefault()); |
| |
| quic_context.AdvanceTime(quic::QuicTime::Delta::FromSeconds(1)); |
| ssl_config_service = std::make_unique<SSLConfigServiceDefaults>(); |
| crypto_client_stream_factory.set_use_mock_crypter(true); |
| cert_verifier = std::make_unique<MockCertVerifier>(); |
| verify_details.cert_verify_result.verified_cert = |
| X509Certificate::CreateFromBytes(kCertData); |
| CHECK(verify_details.cert_verify_result.verified_cert); |
| verify_details.cert_verify_result.is_issued_by_known_root = true; |
| } |
| ~FuzzerEnvironment() = default; |
| |
| std::unique_ptr<SSLConfigService> ssl_config_service; |
| ProofVerifyDetailsChromium verify_details; |
| MockCryptoClientStreamFactory crypto_client_stream_factory; |
| url::SchemeHostPort scheme_host_port; |
| NetLogWithSource net_log; |
| std::unique_ptr<CertVerifier> cert_verifier; |
| TransportSecurityState transport_security_state; |
| quic::QuicTagVector connection_options; |
| quic::QuicTagVector client_connection_options; |
| DefaultCTPolicyEnforcer ct_policy_enforcer; |
| MockQuicContext quic_context; |
| }; |
| |
| FuzzerEnvironment* GetFuzzerEnvironment() { |
| static base::NoDestructor<FuzzerEnvironment> fuzzer_environment; |
| return &*fuzzer_environment; |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| FuzzedDataProvider data_provider(data, size); |
| |
| FuzzerEnvironment* env = GetFuzzerEnvironment(); |
| |
| std::unique_ptr<ContextHostResolver> host_resolver = |
| CreateFuzzedContextHostResolver(HostResolver::ManagerOptions(), nullptr, |
| &data_provider, |
| true /* enable_caching */); |
| FuzzedSocketFactory socket_factory(&data_provider); |
| |
| // Initialize this on each loop since some options mutate this. |
| HttpServerProperties http_server_properties; |
| |
| QuicParams& params = *env->quic_context.params(); |
| params.max_server_configs_stored_in_properties = |
| data_provider.ConsumeBool() ? 1 : 0; |
| params.close_sessions_on_ip_change = data_provider.ConsumeBool(); |
| params.allow_server_migration = data_provider.ConsumeBool(); |
| params.estimate_initial_rtt = data_provider.ConsumeBool(); |
| params.enable_socket_recv_optimization = data_provider.ConsumeBool(); |
| params.race_stale_dns_on_connection = data_provider.ConsumeBool(); |
| |
| env->crypto_client_stream_factory.AddProofVerifyDetails(&env->verify_details); |
| |
| params.goaway_sessions_on_ip_change = false; |
| params.migrate_sessions_early_v2 = false; |
| params.migrate_sessions_on_network_change_v2 = false; |
| params.retry_on_alternate_network_before_handshake = false; |
| params.migrate_idle_sessions = false; |
| |
| if (!params.close_sessions_on_ip_change) { |
| params.goaway_sessions_on_ip_change = data_provider.ConsumeBool(); |
| if (!params.goaway_sessions_on_ip_change) { |
| params.migrate_sessions_on_network_change_v2 = |
| data_provider.ConsumeBool(); |
| if (params.migrate_sessions_on_network_change_v2) { |
| params.migrate_sessions_early_v2 = data_provider.ConsumeBool(); |
| params.retry_on_alternate_network_before_handshake = |
| data_provider.ConsumeBool(); |
| params.migrate_idle_sessions = data_provider.ConsumeBool(); |
| } |
| } |
| } |
| |
| std::unique_ptr<QuicStreamFactory> factory = |
| std::make_unique<QuicStreamFactory>( |
| env->net_log.net_log(), host_resolver.get(), |
| env->ssl_config_service.get(), &socket_factory, |
| &http_server_properties, env->cert_verifier.get(), |
| &env->ct_policy_enforcer, &env->transport_security_state, nullptr, |
| nullptr, &env->crypto_client_stream_factory, &env->quic_context); |
| |
| QuicStreamRequest request(factory.get()); |
| TestCompletionCallback callback; |
| NetErrorDetails net_error_details; |
| quic::ParsedQuicVersionVector versions = AllSupportedQuicVersions(); |
| quic::ParsedQuicVersion version = |
| versions[data_provider.ConsumeIntegralInRange<size_t>( |
| 0, versions.size() - 1)]; |
| |
| quic::QuicEnableVersion(version); |
| |
| request.Request( |
| env->scheme_host_port, version, PRIVACY_MODE_DISABLED, DEFAULT_PRIORITY, |
| SocketTag(), NetworkAnonymizationKey(), SecureDnsPolicy::kAllow, |
| true /* use_dns_aliases */, false /* require_dns_https_alpn */, |
| kCertVerifyFlags, GURL(kUrl), env->net_log, &net_error_details, |
| /*failed_on_default_network_callback=*/CompletionOnceCallback(), |
| callback.callback()); |
| |
| callback.WaitForResult(); |
| std::unique_ptr<QuicChromiumClientSession::Handle> session = |
| request.ReleaseSessionHandle(); |
| if (!session) |
| return 0; |
| auto dns_aliases = session->GetDnsAliasesForSessionKey(request.session_key()); |
| auto stream = std::make_unique<QuicHttpStream>(std::move(session), |
| std::move(dns_aliases)); |
| |
| HttpRequestInfo request_info; |
| request_info.method = kMethod; |
| request_info.url = GURL(kUrl); |
| request_info.traffic_annotation = |
| MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); |
| stream->RegisterRequest(&request_info); |
| stream->InitializeStream(true, DEFAULT_PRIORITY, env->net_log, |
| CompletionOnceCallback()); |
| |
| HttpResponseInfo response; |
| HttpRequestHeaders request_headers; |
| if (OK != |
| stream->SendRequest(request_headers, &response, callback.callback())) |
| return 0; |
| |
| // TODO(nedwilliamson): attempt connection migration here |
| int rv = stream->ReadResponseHeaders(callback.callback()); |
| if (rv != OK && rv != ERR_IO_PENDING) { |
| return 0; |
| } |
| callback.WaitForResult(); |
| |
| scoped_refptr<net::IOBuffer> buffer = |
| base::MakeRefCounted<net::IOBuffer>(kBufferSize); |
| rv = stream->ReadResponseBody(buffer.get(), kBufferSize, callback.callback()); |
| if (rv == ERR_IO_PENDING) |
| callback.WaitForResult(); |
| |
| return 0; |
| } |
| |
| } // namespace test |
| } // namespace net |