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

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: Suppress leak 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 int index = data_provider->ConsumeValueInRange(0, dns_requests->size() - 1);
70
71 // Remove the request from the list before waiting on it - this prevents one
72 // of the other callbacks from deleting the callback being waited on.
73 std::unique_ptr<DnsRequest> request = std::move((*dns_requests)[index]);
74 dns_requests->erase(dns_requests->begin() + index);
75 request->WaitUntilDone();
76 }
77
78 // If |dns_requests| is non-empty, attempts to cancel a randomly chosen one of
79 // them and removes it from |dns_requests|. If the one it picks is already
80 // complete, just removes it from the list.
81 static void CancelRequest(
82 net::HostResolver* host_resolver,
83 net::FuzzedDataProvider* data_provider,
84 std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
85 if (dns_requests->empty())
86 return;
87 int index = data_provider->ConsumeValueInRange(0, dns_requests->size() - 1);
88 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;
98
99 // Remove |this| from |dns_requests| and take ownership of it, if it wasn't
100 // already removed from the vector. It may have been removed if this is in a
101 // WaitForRequest call, in which case, do nothing.
102 std::unique_ptr<DnsRequest> self;
103 for (auto request = dns_requests_->begin(); request != dns_requests_->end();
104 ++request) {
105 if (request->get() != this)
106 continue;
107 self = std::move(*request);
108 dns_requests_->erase(request);
109 break;
110 }
111
112 while (true) {
113 bool done = false;
114 switch (data_provider_->ConsumeValueInRange(0, 2)) {
115 case 0:
116 // Quit on 0, or when no data is left.
117 done = true;
118 case 1:
119 CreateRequest(host_resolver_, data_provider_, dns_requests_);
120 break;
121 case 2:
122 CancelRequest(host_resolver_, data_provider_, dns_requests_);
123 break;
124 }
125
126 if (done)
127 break;
128 }
129
130 if (run_loop_)
131 run_loop_->Quit();
132 }
133
134 // Starts the DNS request, using a fuzzed set of parameters.
135 int Start() {
136 const char* host_name = kHostNames[data_provider_->ConsumeValueInRange(
137 0, arraysize(kHostNames) - 1)];
138 net::HostResolver::RequestInfo info(net::HostPortPair(host_name, 80));
139 info.set_address_family(
140 kAddressFamilies[data_provider_->ConsumeValueInRange(
141 0, arraysize(kAddressFamilies) - 1)]);
142 if (data_provider_->ConsumeBool())
143 info.set_host_resolver_flags(net::HOST_RESOLVER_CANONNAME);
144
145 net::RequestPriority priority =
146 static_cast<net::RequestPriority>(data_provider_->ConsumeValueInRange(
147 net::MINIMUM_PRIORITY, net::MAXIMUM_PRIORITY));
148
149 // Decide if should be a cache-only resolution.
150 if (data_provider_->ConsumeBool()) {
151 return host_resolver_->ResolveFromCache(info, &address_list_,
152 net::BoundNetLog());
153 }
154
155 info.set_allow_cached_response(data_provider_->ConsumeBool());
156 return host_resolver_->Resolve(
157 info, priority, &address_list_,
158 base::Bind(&DnsRequest::OnCallback, base::Unretained(this)), &handle_,
159 net::BoundNetLog());
160 }
161
162 // Waits until the request is done, if it isn't done already.
163 void WaitUntilDone() {
164 CHECK(!run_loop_);
165 if (is_running_) {
166 run_loop_.reset(new base::RunLoop());
167 run_loop_->Run();
168 run_loop_.reset();
169 CHECK(!is_running_);
170 }
171 }
172
173 // Cancel the request, if not already completed. Otherwise, does nothing.
174 void Cancel() {
175 if (is_running_)
176 host_resolver_->CancelRequest(handle_);
177 is_running_ = false;
178 }
179
180 net::HostResolver* host_resolver_;
181 net::FuzzedDataProvider* data_provider_;
182 std::vector<std::unique_ptr<DnsRequest>>* dns_requests_;
183
184 net::HostResolver::RequestHandle handle_;
185 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.
203 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
204 {
205 net::FuzzedDataProvider data_provider(data, size);
206 net::TestNetLog net_log;
207
208 net::HostResolver::Options options;
209 options.max_concurrent_resolves = data_provider.ConsumeValueInRange(1, 8);
210 options.enable_caching = data_provider.ConsumeBool();
211 net::FuzzedHostResolver host_resolver(options, &net_log, &data_provider);
212 host_resolver.SetDnsClientEnabled(data_provider.ConsumeBool());
213
214 std::vector<std::unique_ptr<DnsRequest>> dns_requests;
215 while (true) {
216 switch (data_provider.ConsumeValueInRange(0, 3)) {
217 case 0:
218 // Quit on 0, or when no data is left.
219 return 0;
220 case 1:
221 DnsRequest::CreateRequest(&host_resolver, &data_provider,
222 &dns_requests);
223 break;
224 case 2:
225 DnsRequest::WaitForRequestComplete(&data_provider, &dns_requests);
226 break;
227 case 3:
228 DnsRequest::CancelRequest(&host_resolver, &data_provider,
229 &dns_requests);
230 break;
231 }
232 }
233 }
234
235 // Clean up any pending tasks, after deleting everything.
236 base::RunLoop().RunUntilIdle();
237
238 return 0;
239 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698