// 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_session_pool.h" #include #include #include "base/no_destructor.h" #include "base/task/sequenced_task_runner.h" #include "net/base/network_anonymization_key.h" #include "net/base/privacy_mode.h" #include "net/base/proxy_chain.h" #include "net/base/session_usage.h" #include "net/base/test_completion_callback.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/quic_session_key.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(); crypto_client_stream_factory.set_use_mock_crypter(true); cert_verifier = std::make_unique(); 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 ssl_config_service; ProofVerifyDetailsChromium verify_details; MockCryptoClientStreamFactory crypto_client_stream_factory; url::SchemeHostPort scheme_host_port; NetLogWithSource net_log; std::unique_ptr cert_verifier; TransportSecurityState transport_security_state; quic::QuicTagVector connection_options; quic::QuicTagVector client_connection_options; MockQuicContext quic_context; }; FuzzerEnvironment* GetFuzzerEnvironment() { static base::NoDestructor 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 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(); 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 factory = std::make_unique( env->net_log.net_log(), host_resolver.get(), env->ssl_config_service.get(), &socket_factory, &http_server_properties, env->cert_verifier.get(), &env->transport_security_state, nullptr, nullptr, nullptr, &env->crypto_client_stream_factory, &env->quic_context); QuicSessionRequest request(factory.get()); TestCompletionCallback callback; NetErrorDetails net_error_details; quic::ParsedQuicVersionVector versions = AllSupportedQuicVersions(); quic::ParsedQuicVersion version = versions[data_provider.ConsumeIntegralInRange( 0, versions.size() - 1)]; quic::QuicEnableVersion(version); request.Request( env->scheme_host_port, version, ProxyChain::Direct(), TRAFFIC_ANNOTATION_FOR_TESTS, /*http_user_agent_settings=*/nullptr, SessionUsage::kDestination, PRIVACY_MODE_DISABLED, DEFAULT_PRIORITY, SocketTag(), NetworkAnonymizationKey(), SecureDnsPolicy::kAllow, /*require_dns_https_alpn=*/false, kCertVerifyFlags, GURL(kUrl), env->net_log, &net_error_details, /*failed_on_default_network_callback=*/CompletionOnceCallback(), callback.callback()); callback.WaitForResult(); std::unique_ptr session = request.ReleaseSessionHandle(); if (!session) { return 0; } auto dns_aliases = session->GetDnsAliasesForSessionKey(request.session_key()); auto stream = std::make_unique(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(); auto buffer = base::MakeRefCounted(kBufferSize); rv = stream->ReadResponseBody(buffer.get(), kBufferSize, callback.callback()); if (rv == ERR_IO_PENDING) { callback.WaitForResult(); } return 0; } } // namespace test } // namespace net