210 lines
7.9 KiB
C++
210 lines
7.9 KiB
C++
// 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
|