blob: 2718106abc7cdea9a0e1ed0dd862c581c2c1e4ee [file] [log] [blame]
mmenke91c17162016-06-02 16:03:231// Copyright 2016 The Chromium Authors. All rights reserved.
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 <stddef.h>
6#include <stdint.h>
7
8#include <memory>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/logging.h"
13#include "base/run_loop.h"
csharrisonf30fc95f2016-08-19 21:43:4414#include "base/test/fuzzed_data_provider.h"
Miriam Gershensone42adb22017-10-16 16:19:3815#include "base/test/scoped_task_environment.h"
mmenke91c17162016-06-02 16:03:2316#include "net/base/address_family.h"
17#include "net/base/address_list.h"
mmenke91c17162016-06-02 16:03:2318#include "net/base/net_errors.h"
19#include "net/base/request_priority.h"
20#include "net/dns/fuzzed_host_resolver.h"
21#include "net/dns/host_resolver.h"
mikecironef22f9812016-10-04 03:40:1922#include "net/log/net_log_with_source.h"
mmenke91c17162016-06-02 16:03:2323#include "net/log/test_net_log.h"
24
25namespace {
26
27const char* kHostNames[] = {"foo", "foo.com", "a.foo.com",
28 "bar", "localhost", "localhost6"};
29
30net::AddressFamily kAddressFamilies[] = {
31 net::ADDRESS_FAMILY_UNSPECIFIED, net::ADDRESS_FAMILY_IPV4,
32 net::ADDRESS_FAMILY_IPV6,
33};
34
35class DnsRequest {
36 public:
37 DnsRequest(net::HostResolver* host_resolver,
csharrisonf30fc95f2016-08-19 21:43:4438 base::FuzzedDataProvider* data_provider,
mmenke91c17162016-06-02 16:03:2339 std::vector<std::unique_ptr<DnsRequest>>* dns_requests)
40 : host_resolver_(host_resolver),
41 data_provider_(data_provider),
42 dns_requests_(dns_requests),
mmenke91c17162016-06-02 16:03:2343 is_running_(false) {}
44
Chris Watkins68b15032017-12-01 03:07:1345 ~DnsRequest() = default;
mmenke91c17162016-06-02 16:03:2346
47 // Creates and starts a DNS request using fuzzed parameters. If the request
48 // doesn't complete synchronously, adds it to |dns_requests|.
49 static void CreateRequest(
50 net::HostResolver* host_resolver,
csharrisonf30fc95f2016-08-19 21:43:4451 base::FuzzedDataProvider* data_provider,
mmenke91c17162016-06-02 16:03:2352 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
53 std::unique_ptr<DnsRequest> dns_request(
54 new DnsRequest(host_resolver, data_provider, dns_requests));
55
56 if (dns_request->Start() == net::ERR_IO_PENDING)
57 dns_requests->push_back(std::move(dns_request));
58 }
59
60 // If |dns_requests| is non-empty, waits for a randomly chosen one of the
61 // requests to complete and removes it from |dns_requests|.
62 static void WaitForRequestComplete(
csharrisonf30fc95f2016-08-19 21:43:4463 base::FuzzedDataProvider* data_provider,
mmenke91c17162016-06-02 16:03:2364 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
65 if (dns_requests->empty())
66 return;
Abhishek Arya5b644f62018-11-28 00:47:1767 uint32_t index = data_provider->ConsumeIntegralInRange<uint32_t>(
68 0, dns_requests->size() - 1);
mmenke91c17162016-06-02 16:03:2369
70 // Remove the request from the list before waiting on it - this prevents one
71 // of the other callbacks from deleting the callback being waited on.
72 std::unique_ptr<DnsRequest> request = std::move((*dns_requests)[index]);
73 dns_requests->erase(dns_requests->begin() + index);
74 request->WaitUntilDone();
75 }
76
77 // If |dns_requests| is non-empty, attempts to cancel a randomly chosen one of
78 // them and removes it from |dns_requests|. If the one it picks is already
79 // complete, just removes it from the list.
80 static void CancelRequest(
81 net::HostResolver* host_resolver,
csharrisonf30fc95f2016-08-19 21:43:4482 base::FuzzedDataProvider* data_provider,
mmenke91c17162016-06-02 16:03:2383 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
84 if (dns_requests->empty())
85 return;
Abhishek Arya5b644f62018-11-28 00:47:1786 uint32_t index = data_provider->ConsumeIntegralInRange<uint32_t>(
87 0, dns_requests->size() - 1);
mmenke91c17162016-06-02 16:03:2388 auto request = dns_requests->begin() + index;
89 (*request)->Cancel();
90 dns_requests->erase(request);
91 }
92
93 private:
94 void OnCallback(int result) {
95 CHECK_NE(net::ERR_IO_PENDING, result);
96
97 is_running_ = false;
maksim.sisov31452af2016-07-27 06:38:1098 request_.reset();
mmenke91c17162016-06-02 16:03:2399
100 // Remove |this| from |dns_requests| and take ownership of it, if it wasn't
101 // already removed from the vector. It may have been removed if this is in a
102 // WaitForRequest call, in which case, do nothing.
103 std::unique_ptr<DnsRequest> self;
104 for (auto request = dns_requests_->begin(); request != dns_requests_->end();
105 ++request) {
106 if (request->get() != this)
107 continue;
108 self = std::move(*request);
109 dns_requests_->erase(request);
110 break;
111 }
112
113 while (true) {
114 bool done = false;
Abhishek Arya5b644f62018-11-28 00:47:17115 switch (data_provider_->ConsumeIntegralInRange(0, 2)) {
mmenke91c17162016-06-02 16:03:23116 case 0:
117 // Quit on 0, or when no data is left.
118 done = true;
119 break;
120 case 1:
121 CreateRequest(host_resolver_, data_provider_, dns_requests_);
122 break;
123 case 2:
124 CancelRequest(host_resolver_, data_provider_, dns_requests_);
125 break;
126 }
127
128 if (done)
129 break;
130 }
131
132 if (run_loop_)
133 run_loop_->Quit();
134 }
135
136 // Starts the DNS request, using a fuzzed set of parameters.
137 int Start() {
138 const char* hostname = data_provider_->PickValueInArray(kHostNames);
139 net::HostResolver::RequestInfo info(net::HostPortPair(hostname, 80));
140 info.set_address_family(data_provider_->PickValueInArray(kAddressFamilies));
141 if (data_provider_->ConsumeBool())
142 info.set_host_resolver_flags(net::HOST_RESOLVER_CANONNAME);
143
Abhishek Arya5b644f62018-11-28 00:47:17144 net::RequestPriority priority = static_cast<net::RequestPriority>(
145 data_provider_->ConsumeIntegralInRange<int32_t>(net::MINIMUM_PRIORITY,
146 net::MAXIMUM_PRIORITY));
mmenke91c17162016-06-02 16:03:23147
148 // Decide if should be a cache-only resolution.
149 if (data_provider_->ConsumeBool()) {
150 return host_resolver_->ResolveFromCache(info, &address_list_,
tfarina428341112016-09-22 13:38:20151 net::NetLogWithSource());
mmenke91c17162016-06-02 16:03:23152 }
153
154 info.set_allow_cached_response(data_provider_->ConsumeBool());
Miriam Gershenson01d1d1c152017-09-22 18:21:23155 int rv = host_resolver_->Resolve(
mmenke91c17162016-06-02 16:03:23156 info, priority, &address_list_,
maksim.sisov31452af2016-07-27 06:38:10157 base::Bind(&DnsRequest::OnCallback, base::Unretained(this)), &request_,
tfarina428341112016-09-22 13:38:20158 net::NetLogWithSource());
Miriam Gershenson01d1d1c152017-09-22 18:21:23159 if (rv == net::ERR_IO_PENDING)
160 is_running_ = true;
161 return rv;
mmenke91c17162016-06-02 16:03:23162 }
163
164 // Waits until the request is done, if it isn't done already.
165 void WaitUntilDone() {
166 CHECK(!run_loop_);
167 if (is_running_) {
168 run_loop_.reset(new base::RunLoop());
169 run_loop_->Run();
170 run_loop_.reset();
mmenke91c17162016-06-02 16:03:23171 }
172 }
173
174 // Cancel the request, if not already completed. Otherwise, does nothing.
175 void Cancel() {
maksim.sisov31452af2016-07-27 06:38:10176 request_.reset();
mmenke91c17162016-06-02 16:03:23177 is_running_ = false;
178 }
179
180 net::HostResolver* host_resolver_;
csharrisonf30fc95f2016-08-19 21:43:44181 base::FuzzedDataProvider* data_provider_;
mmenke91c17162016-06-02 16:03:23182 std::vector<std::unique_ptr<DnsRequest>>* dns_requests_;
183
maksim.sisov31452af2016-07-27 06:38:10184 std::unique_ptr<net::HostResolver::Request> request_;
mmenke91c17162016-06-02 16:03:23185 net::AddressList address_list_;
186
187 bool is_running_;
188
189 std::unique_ptr<base::RunLoop> run_loop_;
190
191 DISALLOW_COPY_AND_ASSIGN(DnsRequest);
192};
193
194} // namespace
195
196// Fuzzer for HostResolverImpl. Fuzzes using both the system resolver and
197// built-in DNS client paths.
198//
199// TODO(mmenke): Add coverage for things this does not cover:
200// * Out of order completion, particularly for the platform resolver path.
201// * Simulate network changes, including both enabling and disabling the
202// async resolver while lookups are active as a result of the change.
203extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
204 {
csharrisonf30fc95f2016-08-19 21:43:44205 base::FuzzedDataProvider data_provider(data, size);
mmenke91c17162016-06-02 16:03:23206 net::TestNetLog net_log;
207
208 net::HostResolver::Options options;
Abhishek Arya5b644f62018-11-28 00:47:17209 options.max_concurrent_resolves =
210 data_provider.ConsumeIntegralInRange(1, 8);
mmenke91c17162016-06-02 16:03:23211 options.enable_caching = data_provider.ConsumeBool();
212 net::FuzzedHostResolver host_resolver(options, &net_log, &data_provider);
213 host_resolver.SetDnsClientEnabled(data_provider.ConsumeBool());
214
215 std::vector<std::unique_ptr<DnsRequest>> dns_requests;
Miriam Gershenson01d1d1c152017-09-22 18:21:23216 bool done = false;
217 while (!done) {
Abhishek Arya5b644f62018-11-28 00:47:17218 switch (data_provider.ConsumeIntegralInRange(0, 3)) {
mmenke91c17162016-06-02 16:03:23219 case 0:
220 // Quit on 0, or when no data is left.
Miriam Gershenson01d1d1c152017-09-22 18:21:23221 done = true;
222 break;
mmenke91c17162016-06-02 16:03:23223 case 1:
224 DnsRequest::CreateRequest(&host_resolver, &data_provider,
225 &dns_requests);
226 break;
227 case 2:
228 DnsRequest::WaitForRequestComplete(&data_provider, &dns_requests);
229 break;
230 case 3:
231 DnsRequest::CancelRequest(&host_resolver, &data_provider,
232 &dns_requests);
233 break;
234 }
235 }
236 }
237
238 // Clean up any pending tasks, after deleting everything.
239 base::RunLoop().RunUntilIdle();
240
241 return 0;
242}