Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(605)

Side by Side Diff: net/dns/host_resolver_impl_fuzzer.cc

Issue 1946793002: net: Add fuzzer for HostResolverImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge, fix build Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // 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"
14 #include "net/base/address_family.h"
15 #include "net/base/address_list.h"
16 #include "net/base/fuzzed_data_provider.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/request_priority.h"
19 #include "net/dns/fuzzed_host_resolver.h"
20 #include "net/dns/host_resolver.h"
21 #include "net/log/test_net_log.h"
22
23 namespace {
24
25 const char* kHostNames[] = {"foo", "foo.com", "a.foo.com",
26 "bar", "localhost", "localhost6"};
27
28 net::AddressFamily kAddressFamilies[] = {
29 net::ADDRESS_FAMILY_UNSPECIFIED, net::ADDRESS_FAMILY_IPV4,
30 net::ADDRESS_FAMILY_IPV6,
31 };
32
33 class DnsRequest {
34 public:
35 DnsRequest(net::HostResolver* host_resolver,
36 net::FuzzedDataProvider* data_provider,
37 std::vector<std::unique_ptr<DnsRequest>>* dns_requests)
38 : host_resolver_(host_resolver),
39 data_provider_(data_provider),
40 dns_requests_(dns_requests),
41 handle_(nullptr),
42 is_running_(false) {}
43
44 ~DnsRequest() {
45 if (is_running_)
46 Cancel();
47 }
48
49 // Creates and starts a DNS request using fuzzed parameters. If the request
50 // doesn't complete synchronously, adds it to |dns_requests|.
51 static void CreateRequest(
52 net::HostResolver* host_resolver,
53 net::FuzzedDataProvider* data_provider,
54 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
55 std::unique_ptr<DnsRequest> dns_request(
56 new DnsRequest(host_resolver, data_provider, dns_requests));
57
58 if (dns_request->Start() == net::ERR_IO_PENDING)
59 dns_requests->push_back(std::move(dns_request));
60 }
61
62 // If |dns_requests| is non-empty, waits for a randomly chosen one of the
63 // requests to complete and removes it from |dns_requests|.
64 static void WaitForRequestComplete(
65 net::FuzzedDataProvider* data_provider,
66 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
67 if (dns_requests->empty())
68 return;
69 uint32_t index =
70 data_provider->ConsumeUint32InRange(0, dns_requests->size() - 1);
71
72 // Remove the request from the list before waiting on it - this prevents one
73 // of the other callbacks from deleting the callback being waited on.
74 std::unique_ptr<DnsRequest> request = std::move((*dns_requests)[index]);
75 dns_requests->erase(dns_requests->begin() + index);
76 request->WaitUntilDone();
77 }
78
79 // If |dns_requests| is non-empty, attempts to cancel a randomly chosen one of
80 // them and removes it from |dns_requests|. If the one it picks is already
81 // complete, just removes it from the list.
82 static void CancelRequest(
83 net::HostResolver* host_resolver,
84 net::FuzzedDataProvider* data_provider,
85 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
86 if (dns_requests->empty())
87 return;
88 uint32_t index =
89 data_provider->ConsumeUint32InRange(0, dns_requests->size() - 1);
90 auto request = dns_requests->begin() + index;
91 (*request)->Cancel();
92 dns_requests->erase(request);
93 }
94
95 private:
96 void OnCallback(int result) {
97 CHECK_NE(net::ERR_IO_PENDING, result);
98
99 is_running_ = false;
100
101 // Remove |this| from |dns_requests| and take ownership of it, if it wasn't
102 // already removed from the vector. It may have been removed if this is in a
103 // WaitForRequest call, in which case, do nothing.
104 std::unique_ptr<DnsRequest> self;
105 for (auto request = dns_requests_->begin(); request != dns_requests_->end();
106 ++request) {
107 if (request->get() != this)
108 continue;
109 self = std::move(*request);
110 dns_requests_->erase(request);
111 break;
112 }
113
114 while (true) {
115 bool done = false;
116 switch (data_provider_->ConsumeInt32InRange(0, 2)) {
117 case 0:
118 // Quit on 0, or when no data is left.
119 done = true;
eroman 2016/06/01 01:47:21 is fallthrough intentional?
mmenke 2016/06/01 21:21:51 Eeee...No, it wasn't. Thanks for catching that!
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_->PickArrayEntry(kHostNames);
139 net::HostResolver::RequestInfo info(net::HostPortPair(hostname, 80));
140 info.set_address_family(data_provider_->PickArrayEntry(kAddressFamilies));
141 if (data_provider_->ConsumeBool())
142 info.set_host_resolver_flags(net::HOST_RESOLVER_CANONNAME);
143
144 net::RequestPriority priority =
145 static_cast<net::RequestPriority>(data_provider_->ConsumeInt32InRange(
146 net::MINIMUM_PRIORITY, net::MAXIMUM_PRIORITY));
147
148 // Decide if should be a cache-only resolution.
149 if (data_provider_->ConsumeBool()) {
150 return host_resolver_->ResolveFromCache(info, &address_list_,
151 net::BoundNetLog());
152 }
153
154 info.set_allow_cached_response(data_provider_->ConsumeBool());
155 return host_resolver_->Resolve(
156 info, priority, &address_list_,
157 base::Bind(&DnsRequest::OnCallback, base::Unretained(this)), &handle_,
158 net::BoundNetLog());
159 }
160
161 // Waits until the request is done, if it isn't done already.
162 void WaitUntilDone() {
163 CHECK(!run_loop_);
164 if (is_running_) {
165 run_loop_.reset(new base::RunLoop());
166 run_loop_->Run();
167 run_loop_.reset();
168 CHECK(!is_running_);
169 }
170 }
171
172 // Cancel the request, if not already completed. Otherwise, does nothing.
173 void Cancel() {
174 if (is_running_)
175 host_resolver_->CancelRequest(handle_);
176 is_running_ = false;
177 }
178
179 net::HostResolver* host_resolver_;
180 net::FuzzedDataProvider* data_provider_;
181 std::vector<std::unique_ptr<DnsRequest>>* dns_requests_;
182
183 net::HostResolver::RequestHandle handle_;
184 net::AddressList address_list_;
185
186 bool is_running_;
187
188 std::unique_ptr<base::RunLoop> run_loop_;
189
190 DISALLOW_COPY_AND_ASSIGN(DnsRequest);
191 };
192
193 } // namespace
194
195 // Fuzzer for HostResolverImpl. Fuzzes using both the system resolver and
196 // built-in DNS client paths.
197 //
198 // TODO(mmenke): Add coverage for things this does not cover:
199 // * Out of order completion, particularly for the platform resolver path.
200 // * Simulate network changes, including both enabling and disabling the
201 // async resolver while lookups are active as a result of the change.
202 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
203 {
204 net::FuzzedDataProvider data_provider(data, size);
205 net::TestNetLog net_log;
206
207 net::HostResolver::Options options;
208 options.max_concurrent_resolves = data_provider.ConsumeUint32InRange(1, 8);
209 options.enable_caching = data_provider.ConsumeBool();
210 net::FuzzedHostResolver host_resolver(options, &net_log, &data_provider);
211 host_resolver.SetDnsClientEnabled(data_provider.ConsumeBool());
212
213 std::vector<std::unique_ptr<DnsRequest>> dns_requests;
214 while (true) {
215 switch (data_provider.ConsumeInt32InRange(0, 3)) {
216 case 0:
217 // Quit on 0, or when no data is left.
218 return 0;
219 case 1:
220 DnsRequest::CreateRequest(&host_resolver, &data_provider,
221 &dns_requests);
222 break;
223 case 2:
224 DnsRequest::WaitForRequestComplete(&data_provider, &dns_requests);
225 break;
226 case 3:
227 DnsRequest::CancelRequest(&host_resolver, &data_provider,
228 &dns_requests);
229 break;
230 }
231 }
232 }
233
234 // Clean up any pending tasks, after deleting everything.
235 base::RunLoop().RunUntilIdle();
236
237 return 0;
238 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698