// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/logging.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/test/fuzzed_data_provider.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" #include "net/base/request_priority.h" #include "net/cert/x509_certificate.h" #include "net/log/net_log_source.h" #include "net/log/test_net_log.h" #include "net/socket/fuzzed_socket_factory.h" #include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/socket/ssl_client_socket.h" #include "net/spdy/spdy_test_util_common.h" #include "net/ssl/ssl_config.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" namespace { const char kCertData[] = { #include "net/data/ssl/certificates/spdy_pooling.inc" }; class FuzzerDelegate : public net::SpdyStream::Delegate { public: explicit FuzzerDelegate(const base::Closure& done_closure) : done_closure_(done_closure) {} void OnHeadersSent() override {} void OnHeadersReceived( const spdy::SpdyHeaderBlock& response_headers, const spdy::SpdyHeaderBlock* pushed_request_headers) override {} void OnDataReceived(std::unique_ptr buffer) override {} void OnDataSent() override {} void OnTrailers(const spdy::SpdyHeaderBlock& trailers) override {} void OnClose(int status) override { done_closure_.Run(); } net::NetLogSource source_dependency() const override { return net::NetLogSource(); } private: base::Closure done_closure_; DISALLOW_COPY_AND_ASSIGN(FuzzerDelegate); }; } // namespace namespace net { namespace { class FuzzedSocketFactoryWithMockSSLData : public FuzzedSocketFactory { public: explicit FuzzedSocketFactoryWithMockSSLData( base::FuzzedDataProvider* data_provider); void AddSSLSocketDataProvider(SSLSocketDataProvider* socket); std::unique_ptr CreateSSLClientSocket( std::unique_ptr nested_socket, const HostPortPair& host_and_port, const SSLConfig& ssl_config, const SSLClientSocketContext& context) override; private: SocketDataProviderArray mock_ssl_data_; }; FuzzedSocketFactoryWithMockSSLData::FuzzedSocketFactoryWithMockSSLData( base::FuzzedDataProvider* data_provider) : FuzzedSocketFactory(data_provider) {} void FuzzedSocketFactoryWithMockSSLData::AddSSLSocketDataProvider( SSLSocketDataProvider* data) { mock_ssl_data_.Add(data); } std::unique_ptr FuzzedSocketFactoryWithMockSSLData::CreateSSLClientSocket( std::unique_ptr nested_socket, const HostPortPair& host_and_port, const SSLConfig& ssl_config, const SSLClientSocketContext& context) { return std::make_unique(std::move(nested_socket), host_and_port, ssl_config, mock_ssl_data_.GetNext()); } } // namespace } // namespace net // Fuzzer for SpdySession // // |data| is used to create a FuzzedServerSocket. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { net::BoundTestNetLog bound_test_net_log; base::FuzzedDataProvider data_provider(data, size); net::FuzzedSocketFactoryWithMockSSLData socket_factory(&data_provider); socket_factory.set_fuzz_connect_result(false); net::SSLSocketDataProvider ssl_provider(net::ASYNC, net::OK); ssl_provider.ssl_info.cert = net::X509Certificate::CreateFromBytes(kCertData, base::size(kCertData)); CHECK(ssl_provider.ssl_info.cert); socket_factory.AddSSLSocketDataProvider(&ssl_provider); net::SpdySessionDependencies deps; std::unique_ptr http_session( net::SpdySessionDependencies::SpdyCreateSessionWithSocketFactory( &deps, &socket_factory)); net::ProxyServer direct_connect(net::ProxyServer::Direct()); net::SpdySessionKey session_key(net::HostPortPair("127.0.0.1", 80), direct_connect, net::PRIVACY_MODE_DISABLED, net::SpdySessionKey::IsProxySession::kFalse, net::SocketTag()); base::WeakPtr spdy_session(net::CreateSpdySession( http_session.get(), session_key, bound_test_net_log.bound())); net::SpdyStreamRequest stream_request; base::WeakPtr stream; net::TestCompletionCallback wait_for_start; int rv = stream_request.StartRequest( net::SPDY_REQUEST_RESPONSE_STREAM, spdy_session, GURL("http://www.example.invalid/"), net::DEFAULT_PRIORITY, net::SocketTag(), bound_test_net_log.bound(), wait_for_start.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); if (rv == net::ERR_IO_PENDING) { rv = wait_for_start.WaitForResult(); } // Re-check the status after potential event loop. if (rv != net::OK) { LOG(WARNING) << "StartRequest failed with result=" << rv; return 0; } stream = stream_request.ReleaseStream(); stream->SendRequestHeaders( net::SpdyTestUtil::ConstructGetHeaderBlock("http://www.example.invalid"), net::NO_MORE_DATA_TO_SEND); base::RunLoop run_loop; FuzzerDelegate delegate(run_loop.QuitClosure()); stream->SetDelegate(&delegate); run_loop.Run(); // Give a chance for GOING_AWAY sessions to wrap up. base::RunLoop().RunUntilIdle(); return 0; }