host_resolver_manager_fuzzer.cc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <fuzzer/FuzzedDataProvider.h>
  7. #include <iterator>
  8. #include <memory>
  9. #include <vector>
  10. #include "base/bind.h"
  11. #include "base/check_op.h"
  12. #include "base/run_loop.h"
  13. #include "base/test/task_environment.h"
  14. #include "net/base/address_family.h"
  15. #include "net/base/address_list.h"
  16. #include "net/base/net_errors.h"
  17. #include "net/base/network_isolation_key.h"
  18. #include "net/base/request_priority.h"
  19. #include "net/dns/context_host_resolver.h"
  20. #include "net/dns/fuzzed_host_resolver_util.h"
  21. #include "net/dns/host_resolver.h"
  22. #include "net/dns/public/dns_query_type.h"
  23. #include "net/dns/public/host_resolver_source.h"
  24. #include "net/log/net_log.h"
  25. #include "net/log/net_log_with_source.h"
  26. #include "net/log/test_net_log.h"
  27. #include "net/net_buildflags.h"
  28. namespace {
  29. const char* kHostNames[] = {"foo", "foo.com", "a.foo.com",
  30. "bar", "localhost", "localhost6"};
  31. class DnsRequest {
  32. public:
  33. DnsRequest(net::HostResolver* host_resolver,
  34. FuzzedDataProvider* data_provider,
  35. std::vector<std::unique_ptr<DnsRequest>>* dns_requests)
  36. : host_resolver_(host_resolver),
  37. data_provider_(data_provider),
  38. dns_requests_(dns_requests) {}
  39. DnsRequest(const DnsRequest&) = delete;
  40. DnsRequest& operator=(const DnsRequest&) = delete;
  41. ~DnsRequest() = default;
  42. // Creates and starts a DNS request using fuzzed parameters. If the request
  43. // doesn't complete synchronously, adds it to |dns_requests|.
  44. static void CreateRequest(
  45. net::HostResolver* host_resolver,
  46. FuzzedDataProvider* data_provider,
  47. std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
  48. auto dns_request = std::make_unique<DnsRequest>(
  49. host_resolver, data_provider, dns_requests);
  50. if (dns_request->Start() == net::ERR_IO_PENDING)
  51. dns_requests->push_back(std::move(dns_request));
  52. }
  53. // If |dns_requests| is non-empty, waits for a randomly chosen one of the
  54. // requests to complete and removes it from |dns_requests|.
  55. static void WaitForRequestComplete(
  56. FuzzedDataProvider* data_provider,
  57. std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
  58. if (dns_requests->empty())
  59. return;
  60. uint32_t index = data_provider->ConsumeIntegralInRange<uint32_t>(
  61. 0, dns_requests->size() - 1);
  62. // Remove the request from the list before waiting on it - this prevents one
  63. // of the other callbacks from deleting the callback being waited on.
  64. std::unique_ptr<DnsRequest> request = std::move((*dns_requests)[index]);
  65. dns_requests->erase(dns_requests->begin() + index);
  66. request->WaitUntilDone();
  67. }
  68. // If |dns_requests| is non-empty, attempts to cancel a randomly chosen one of
  69. // them and removes it from |dns_requests|. If the one it picks is already
  70. // complete, just removes it from the list.
  71. static void CancelRequest(
  72. net::HostResolver* host_resolver,
  73. FuzzedDataProvider* data_provider,
  74. std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
  75. if (dns_requests->empty())
  76. return;
  77. uint32_t index = data_provider->ConsumeIntegralInRange<uint32_t>(
  78. 0, dns_requests->size() - 1);
  79. auto request = dns_requests->begin() + index;
  80. (*request)->Cancel();
  81. dns_requests->erase(request);
  82. }
  83. private:
  84. void OnCallback(int result) {
  85. CHECK_NE(net::ERR_IO_PENDING, result);
  86. request_.reset();
  87. // Remove |this| from |dns_requests| and take ownership of it, if it wasn't
  88. // already removed from the vector. It may have been removed if this is in a
  89. // WaitForRequest call, in which case, do nothing.
  90. std::unique_ptr<DnsRequest> self;
  91. for (auto request = dns_requests_->begin(); request != dns_requests_->end();
  92. ++request) {
  93. if (request->get() != this)
  94. continue;
  95. self = std::move(*request);
  96. dns_requests_->erase(request);
  97. break;
  98. }
  99. while (true) {
  100. bool done = false;
  101. switch (data_provider_->ConsumeIntegralInRange(0, 2)) {
  102. case 0:
  103. // Quit on 0, or when no data is left.
  104. done = true;
  105. break;
  106. case 1:
  107. CreateRequest(host_resolver_, data_provider_, dns_requests_);
  108. break;
  109. case 2:
  110. CancelRequest(host_resolver_, data_provider_, dns_requests_);
  111. break;
  112. }
  113. if (done)
  114. break;
  115. }
  116. if (run_loop_)
  117. run_loop_->Quit();
  118. }
  119. // Starts the DNS request, using a fuzzed set of parameters.
  120. int Start() {
  121. net::HostResolver::ResolveHostParameters parameters;
  122. auto* query_types_it = net::kDnsQueryTypes.cbegin();
  123. std::advance(query_types_it, data_provider_->ConsumeIntegralInRange<size_t>(
  124. 0, net::kDnsQueryTypes.size() - 1));
  125. parameters.dns_query_type = query_types_it->first;
  126. parameters.initial_priority = static_cast<net::RequestPriority>(
  127. data_provider_->ConsumeIntegralInRange<int32_t>(net::MINIMUM_PRIORITY,
  128. net::MAXIMUM_PRIORITY));
  129. parameters.source =
  130. data_provider_->PickValueInArray(net::kHostResolverSources);
  131. #if !BUILDFLAG(ENABLE_MDNS)
  132. while (parameters.source == net::HostResolverSource::MULTICAST_DNS) {
  133. parameters.source =
  134. data_provider_->PickValueInArray(net::kHostResolverSources);
  135. }
  136. #endif // !BUILDFLAG(ENABLE_MDNS)
  137. parameters.cache_usage =
  138. data_provider_->ConsumeBool()
  139. ? net::HostResolver::ResolveHostParameters::CacheUsage::ALLOWED
  140. : net::HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
  141. // `include_canonical_name` only allowed for address queries and only when
  142. // the system resolver can be used.
  143. if (net::IsAddressType(parameters.dns_query_type) &&
  144. parameters.source != net::HostResolverSource::DNS &&
  145. parameters.source != net::HostResolverSource::MULTICAST_DNS) {
  146. parameters.include_canonical_name = data_provider_->ConsumeBool();
  147. }
  148. if (!IsParameterCombinationAllowed(parameters)) {
  149. return net::ERR_FAILED;
  150. }
  151. const char* hostname = data_provider_->PickValueInArray(kHostNames);
  152. request_ = host_resolver_->CreateRequest(
  153. net::HostPortPair(hostname, 80), net::NetworkIsolationKey(),
  154. net::NetLogWithSource(), parameters);
  155. int rv = request_->Start(
  156. base::BindOnce(&DnsRequest::OnCallback, base::Unretained(this)));
  157. if (rv != net::ERR_IO_PENDING)
  158. request_.reset();
  159. return rv;
  160. }
  161. // Waits until the request is done, if it isn't done already.
  162. void WaitUntilDone() {
  163. CHECK(!run_loop_);
  164. if (request_) {
  165. run_loop_ = std::make_unique<base::RunLoop>();
  166. run_loop_->Run();
  167. run_loop_.reset();
  168. }
  169. }
  170. // Some combinations of request parameters are disallowed and expected to
  171. // DCHECK. Returns whether or not |parameters| represents one of those cases.
  172. static bool IsParameterCombinationAllowed(
  173. net::HostResolver::ResolveHostParameters parameters) {
  174. // SYSTEM requests only support address types.
  175. if (parameters.source == net::HostResolverSource::SYSTEM &&
  176. !net::IsAddressType(parameters.dns_query_type)) {
  177. return false;
  178. }
  179. // Multiple parameters disallowed for mDNS requests.
  180. if (parameters.source == net::HostResolverSource::MULTICAST_DNS &&
  181. (parameters.include_canonical_name || parameters.loopback_only ||
  182. parameters.cache_usage !=
  183. net::HostResolver::ResolveHostParameters::CacheUsage::ALLOWED)) {
  184. return false;
  185. }
  186. return true;
  187. }
  188. // Cancel the request, if not already completed. Otherwise, does nothing.
  189. void Cancel() { request_.reset(); }
  190. net::HostResolver* host_resolver_;
  191. FuzzedDataProvider* data_provider_;
  192. std::vector<std::unique_ptr<DnsRequest>>* dns_requests_;
  193. // Non-null only while running.
  194. std::unique_ptr<net::HostResolver::ResolveHostRequest> request_;
  195. net::AddressList address_list_;
  196. std::unique_ptr<base::RunLoop> run_loop_;
  197. };
  198. } // namespace
  199. // Fuzzer for HostResolverImpl. Fuzzes using both the system resolver and
  200. // built-in DNS client paths.
  201. //
  202. // TODO(mmenke): Add coverage for things this does not cover:
  203. // * Out of order completion, particularly for the platform resolver path.
  204. // * Simulate network changes, including both enabling and disabling the
  205. // async resolver while lookups are active as a result of the change.
  206. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  207. {
  208. FuzzedDataProvider data_provider(data, size);
  209. // Including an observer; even though the recorded results aren't currently
  210. // used, it'll ensure the netlogging code is fuzzed as well.
  211. net::RecordingNetLogObserver net_log_observer;
  212. net::HostResolver::ManagerOptions options;
  213. options.max_concurrent_resolves =
  214. data_provider.ConsumeIntegralInRange(1, 8);
  215. options.insecure_dns_client_enabled = data_provider.ConsumeBool();
  216. bool enable_caching = data_provider.ConsumeBool();
  217. std::unique_ptr<net::ContextHostResolver> host_resolver =
  218. net::CreateFuzzedContextHostResolver(options, net::NetLog::Get(),
  219. &data_provider, enable_caching);
  220. std::vector<std::unique_ptr<DnsRequest>> dns_requests;
  221. bool done = false;
  222. while (!done) {
  223. switch (data_provider.ConsumeIntegralInRange(0, 3)) {
  224. case 0:
  225. // Quit on 0, or when no data is left.
  226. done = true;
  227. break;
  228. case 1:
  229. DnsRequest::CreateRequest(host_resolver.get(), &data_provider,
  230. &dns_requests);
  231. break;
  232. case 2:
  233. DnsRequest::WaitForRequestComplete(&data_provider, &dns_requests);
  234. break;
  235. case 3:
  236. DnsRequest::CancelRequest(host_resolver.get(), &data_provider,
  237. &dns_requests);
  238. break;
  239. }
  240. }
  241. }
  242. // Clean up any pending tasks, after deleting everything.
  243. base::RunLoop().RunUntilIdle();
  244. return 0;
  245. }