• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include <string.h>
20 
21 #include <algorithm>
22 #include <atomic>
23 #include <functional>
24 #include <initializer_list>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "absl/status/status.h"
31 #include "absl/status/statusor.h"
32 #include "absl/strings/str_join.h"
33 #include "absl/strings/str_split.h"
34 #include "absl/strings/string_view.h"
35 #include "absl/types/optional.h"
36 
37 #include <grpc/event_engine/event_engine.h>
38 #include <grpc/grpc.h>
39 #include <grpc/grpc_security.h>
40 #include <grpc/support/alloc.h>
41 #include <grpc/support/log.h>
42 #include <grpc/support/string_util.h>
43 
44 #include "src/core/ext/transport/inproc/inproc_transport.h"
45 #include "src/core/lib/address_utils/parse_address.h"
46 #include "src/core/lib/channel/channel_args.h"
47 #include "src/core/lib/event_engine/default_event_engine.h"
48 #include "src/core/lib/experiments/config.h"
49 #include "src/core/lib/gprpp/debug_location.h"
50 #include "src/core/lib/gprpp/env.h"
51 #include "src/core/lib/gprpp/ref_counted_ptr.h"
52 #include "src/core/lib/gprpp/time.h"
53 #include "src/core/lib/iomgr/closure.h"
54 #include "src/core/lib/iomgr/exec_ctx.h"
55 #include "src/core/lib/iomgr/iomgr_fwd.h"
56 #include "src/core/lib/iomgr/resolve_address.h"
57 #include "src/core/lib/iomgr/resolved_address.h"
58 #include "src/core/resolver/dns/c_ares/grpc_ares_wrapper.h"
59 #include "src/core/resolver/endpoint_addresses.h"
60 #include "src/libfuzzer/libfuzzer_macro.h"
61 #include "test/core/end2end/data/ssl_test_data.h"
62 #include "test/core/end2end/fuzzers/api_fuzzer.pb.h"
63 #include "test/core/end2end/fuzzers/fuzzing_common.h"
64 #include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
65 #include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h"
66 #include "test/core/util/fuzz_config_vars.h"
67 #include "test/core/util/fuzzing_channel_args.h"
68 
69 // IWYU pragma: no_include <google/protobuf/repeated_ptr_field.h>
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 // logging
73 
74 bool squelch = true;
75 bool leak_check = true;
76 
dont_log(gpr_log_func_args *)77 static void dont_log(gpr_log_func_args* /*args*/) {}
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 // dns resolution
81 
82 typedef struct addr_req {
83   char* addr;
84   grpc_closure* on_done;
85   std::unique_ptr<grpc_core::EndpointAddressesList>* addresses;
86 } addr_req;
87 
finish_resolve(addr_req r)88 static void finish_resolve(addr_req r) {
89   if (0 == strcmp(r.addr, "server")) {
90     *r.addresses = std::make_unique<grpc_core::EndpointAddressesList>();
91     grpc_resolved_address fake_resolved_address;
92     GPR_ASSERT(
93         grpc_parse_ipv4_hostport("1.2.3.4:5", &fake_resolved_address, false));
94     (*r.addresses)
95         ->emplace_back(fake_resolved_address, grpc_core::ChannelArgs());
96     grpc_core::ExecCtx::Run(DEBUG_LOCATION, r.on_done, absl::OkStatus());
97   } else {
98     grpc_core::ExecCtx::Run(DEBUG_LOCATION, r.on_done,
99                             absl::UnknownError("Resolution failed"));
100   }
101   gpr_free(r.addr);
102 }
103 
104 namespace {
105 
106 using grpc_event_engine::experimental::FuzzingEventEngine;
107 using grpc_event_engine::experimental::GetDefaultEventEngine;
108 
109 class FuzzerDNSResolver : public grpc_core::DNSResolver {
110  public:
111   class FuzzerDNSRequest {
112    public:
FuzzerDNSRequest(absl::string_view name,std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_done)113     FuzzerDNSRequest(
114         absl::string_view name,
115         std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
116             on_done)
117         : name_(std::string(name)), on_done_(std::move(on_done)) {
118       GetDefaultEventEngine()->RunAfter(
119           grpc_core::Duration::Seconds(1), [this] {
120             grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
121             grpc_core::ExecCtx exec_ctx;
122             FinishResolve();
123           });
124     }
125 
126    private:
FinishResolve()127     void FinishResolve() {
128       if (name_ == "server") {
129         std::vector<grpc_resolved_address> addrs;
130         grpc_resolved_address addr;
131         memset(&addr, 0, sizeof(addr));
132         addrs.push_back(addr);
133         on_done_(std::move(addrs));
134       } else {
135         on_done_(absl::UnknownError("Resolution failed"));
136       }
137       delete this;
138     }
139 
140     const std::string name_;
141     const std::function<void(
142         absl::StatusOr<std::vector<grpc_resolved_address>>)>
143         on_done_;
144   };
145 
FuzzerDNSResolver(FuzzingEventEngine * engine)146   explicit FuzzerDNSResolver(FuzzingEventEngine* engine) : engine_(engine) {}
147 
LookupHostname(std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolved,absl::string_view name,absl::string_view,grpc_core::Duration,grpc_pollset_set *,absl::string_view)148   TaskHandle LookupHostname(
149       std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
150           on_resolved,
151       absl::string_view name, absl::string_view /* default_port */,
152       grpc_core::Duration /* timeout */,
153       grpc_pollset_set* /* interested_parties */,
154       absl::string_view /* name_server */) override {
155     new FuzzerDNSRequest(name, std::move(on_resolved));
156     return kNullHandle;
157   }
158 
LookupHostnameBlocking(absl::string_view,absl::string_view)159   absl::StatusOr<std::vector<grpc_resolved_address>> LookupHostnameBlocking(
160       absl::string_view /* name */,
161       absl::string_view /* default_port */) override {
162     GPR_ASSERT(0);
163   }
164 
LookupSRV(std::function<void (absl::StatusOr<std::vector<grpc_resolved_address>>)> on_resolved,absl::string_view,grpc_core::Duration,grpc_pollset_set *,absl::string_view)165   TaskHandle LookupSRV(
166       std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
167           on_resolved,
168       absl::string_view /* name */, grpc_core::Duration /* timeout */,
169       grpc_pollset_set* /* interested_parties */,
170       absl::string_view /* name_server */) override {
171     engine_->Run([on_resolved] {
172       grpc_core::ApplicationCallbackExecCtx app_exec_ctx;
173       grpc_core::ExecCtx exec_ctx;
174       on_resolved(absl::UnimplementedError(
175           "The Fuzzing DNS resolver does not support looking up SRV records"));
176     });
177     return {-1, -1};
178   };
179 
LookupTXT(std::function<void (absl::StatusOr<std::string>)> on_resolved,absl::string_view,grpc_core::Duration,grpc_pollset_set *,absl::string_view)180   TaskHandle LookupTXT(
181       std::function<void(absl::StatusOr<std::string>)> on_resolved,
182       absl::string_view /* name */, grpc_core::Duration /* timeout */,
183       grpc_pollset_set* /* interested_parties */,
184       absl::string_view /* name_server */) override {
185     // Not supported
186     engine_->Run([on_resolved] {
187       grpc_core::ApplicationCallbackExecCtx app_exec_ctx;
188       grpc_core::ExecCtx exec_ctx;
189       on_resolved(absl::UnimplementedError(
190           "The Fuzing DNS resolver does not support looking up TXT records"));
191     });
192     return {-1, -1};
193   };
194 
195   // FuzzerDNSResolver does not support cancellation.
Cancel(TaskHandle)196   bool Cancel(TaskHandle /*handle*/) override { return false; }
197 
198  private:
199   FuzzingEventEngine* engine_;
200 };
201 
202 }  // namespace
203 
my_dns_lookup_ares(const char *,const char * addr,const char *,grpc_pollset_set *,grpc_closure * on_done,std::unique_ptr<grpc_core::EndpointAddressesList> * addresses,int)204 grpc_ares_request* my_dns_lookup_ares(
205     const char* /*dns_server*/, const char* addr, const char* /*default_port*/,
206     grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done,
207     std::unique_ptr<grpc_core::EndpointAddressesList>* addresses,
208     int /*query_timeout*/) {
209   addr_req r;
210   r.addr = gpr_strdup(addr);
211   r.on_done = on_done;
212   r.addresses = addresses;
213   GetDefaultEventEngine()->RunAfter(grpc_core::Duration::Seconds(1), [r] {
214     grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
215     grpc_core::ExecCtx exec_ctx;
216     finish_resolve(r);
217   });
218   return nullptr;
219 }
220 
my_cancel_ares_request(grpc_ares_request * request)221 static void my_cancel_ares_request(grpc_ares_request* request) {
222   GPR_ASSERT(request == nullptr);
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 // globals
227 
228 namespace grpc_core {
229 namespace testing {
230 
231 class ApiFuzzer final : public BasicFuzzer {
232  public:
233   explicit ApiFuzzer(const fuzzing_event_engine::Actions& actions);
234   ~ApiFuzzer();
235   void Tick() override;
Server()236   grpc_server* Server() { return server_; }
237 
238  private:
239   Result CreateChannel(
240       const api_fuzzer::CreateChannel& create_channel) override;
241 
242   Result CreateServer(const api_fuzzer::CreateServer& create_server) override;
243   void DestroyServer() override;
244   void DestroyChannel() override;
245 
server()246   grpc_server* server() override { return server_; }
channel()247   grpc_channel* channel() override { return channel_; }
248 
249   grpc_server* server_ = nullptr;
250   grpc_channel* channel_ = nullptr;
251   std::atomic<bool> channel_force_delete_{false};
252 };
253 
254 }  // namespace testing
255 }  // namespace grpc_core
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 // test driver
259 
ReadCredArtifact(const api_fuzzer::CredArtifact & artifact,std::initializer_list<const char * > builtins)260 static const char* ReadCredArtifact(
261     const api_fuzzer::CredArtifact& artifact,
262     std::initializer_list<const char*> builtins) {
263   switch (artifact.type_case()) {
264     case api_fuzzer::CredArtifact::kCustom:
265       return artifact.custom().c_str();
266     case api_fuzzer::CredArtifact::kBuiltin:
267       if (artifact.builtin() < 0) return nullptr;
268       if (artifact.builtin() < static_cast<int>(builtins.size())) {
269         return *(builtins.begin() + artifact.builtin());
270       }
271       return nullptr;
272     case api_fuzzer::CredArtifact::TYPE_NOT_SET:
273       return nullptr;
274   }
275 }
276 
ReadSslChannelCreds(const api_fuzzer::SslChannelCreds & creds)277 static grpc_channel_credentials* ReadSslChannelCreds(
278     const api_fuzzer::SslChannelCreds& creds) {
279   const char* root_certs =
280       creds.has_root_certs()
281           ? ReadCredArtifact(creds.root_certs(), {test_root_cert})
282           : nullptr;
283   const char* private_key =
284       creds.has_private_key()
285           ? ReadCredArtifact(creds.private_key(),
286                              {test_server1_key, test_self_signed_client_key,
287                               test_signed_client_key})
288           : nullptr;
289   const char* certs =
290       creds.has_certs()
291           ? ReadCredArtifact(creds.certs(),
292                              {test_server1_cert, test_self_signed_client_cert,
293                               test_signed_client_cert})
294           : nullptr;
295   grpc_ssl_pem_key_cert_pair key_cert_pair = {private_key, certs};
296   return grpc_ssl_credentials_create(
297       root_certs,
298       private_key != nullptr && certs != nullptr ? &key_cert_pair : nullptr,
299       nullptr, nullptr);
300 }
301 
ReadCallCreds(const api_fuzzer::CallCreds & creds)302 static grpc_call_credentials* ReadCallCreds(
303     const api_fuzzer::CallCreds& creds) {
304   switch (creds.type_case()) {
305     case api_fuzzer::CallCreds::TYPE_NOT_SET:
306       return nullptr;
307     case api_fuzzer::CallCreds::kNull:
308       return nullptr;
309     case api_fuzzer::CallCreds::kCompositeCallCreds: {
310       grpc_call_credentials* out = nullptr;
311       for (const auto& child_creds :
312            creds.composite_call_creds().call_creds()) {
313         grpc_call_credentials* child = ReadCallCreds(child_creds);
314         if (child != nullptr) {
315           if (out == nullptr) {
316             out = child;
317           } else {
318             auto* composed =
319                 grpc_composite_call_credentials_create(out, child, nullptr);
320             grpc_call_credentials_release(child);
321             grpc_call_credentials_release(out);
322             out = composed;
323           }
324         }
325       }
326       return out;
327     }
328     case api_fuzzer::CallCreds::kAccessToken:
329       return grpc_access_token_credentials_create(creds.access_token().c_str(),
330                                                   nullptr);
331     case api_fuzzer::CallCreds::kIam:
332       return grpc_google_iam_credentials_create(
333           creds.iam().auth_token().c_str(), creds.iam().auth_selector().c_str(),
334           nullptr);
335       // TODO(ctiller): more cred types here
336   }
337 }
338 
ReadChannelCreds(const api_fuzzer::ChannelCreds & creds)339 static grpc_channel_credentials* ReadChannelCreds(
340     const api_fuzzer::ChannelCreds& creds) {
341   switch (creds.type_case()) {
342     case api_fuzzer::ChannelCreds::TYPE_NOT_SET:
343       return nullptr;
344     case api_fuzzer::ChannelCreds::kSslChannelCreds:
345       return ReadSslChannelCreds(creds.ssl_channel_creds());
346     case api_fuzzer::ChannelCreds::kCompositeChannelCreds: {
347       const auto& comp = creds.composite_channel_creds();
348       grpc_channel_credentials* c1 =
349           comp.has_channel_creds() ? ReadChannelCreds(comp.channel_creds())
350                                    : nullptr;
351       grpc_call_credentials* c2 =
352           comp.has_call_creds() ? ReadCallCreds(comp.call_creds()) : nullptr;
353       if (c1 != nullptr && c2 != nullptr) {
354         grpc_channel_credentials* out =
355             grpc_composite_channel_credentials_create(c1, c2, nullptr);
356         grpc_channel_credentials_release(c1);
357         grpc_call_credentials_release(c2);
358         return out;
359       } else if (c1 != nullptr) {
360         return c1;
361       } else if (c2 != nullptr) {
362         grpc_call_credentials_release(c2);
363         return nullptr;
364       } else {
365         return nullptr;
366       }
367       GPR_UNREACHABLE_CODE(return nullptr);
368     }
369     case api_fuzzer::ChannelCreds::kNull:
370       return nullptr;
371   }
372 }
373 
ReadServerCreds(const api_fuzzer::ServerCreds & creds)374 static grpc_server_credentials* ReadServerCreds(
375     const api_fuzzer::ServerCreds& creds) {
376   switch (creds.type_case()) {
377     case api_fuzzer::ServerCreds::TYPE_NOT_SET:
378       return nullptr;
379     case api_fuzzer::ServerCreds::kInsecureCreds:
380       return grpc_insecure_server_credentials_create();
381     case api_fuzzer::ServerCreds::kNull:
382       return nullptr;
383   }
384 }
385 
386 namespace grpc_core {
387 namespace testing {
388 
ApiFuzzer(const fuzzing_event_engine::Actions & actions)389 ApiFuzzer::ApiFuzzer(const fuzzing_event_engine::Actions& actions)
390     : BasicFuzzer(actions) {
391   ResetDNSResolver(std::make_unique<FuzzerDNSResolver>(engine()));
392   grpc_dns_lookup_hostname_ares = my_dns_lookup_ares;
393   grpc_cancel_ares_request = my_cancel_ares_request;
394 
395   GPR_ASSERT(channel_ == nullptr);
396   GPR_ASSERT(server_ == nullptr);
397 }
398 
~ApiFuzzer()399 ApiFuzzer::~ApiFuzzer() {
400   GPR_ASSERT(channel_ == nullptr);
401   GPR_ASSERT(server_ == nullptr);
402 }
403 
Tick()404 void ApiFuzzer::Tick() {
405   BasicFuzzer::Tick();
406   if (channel_force_delete_.exchange(false) && channel_) {
407     grpc_channel_destroy(channel_);
408     channel_ = nullptr;
409   }
410 }
411 
412 namespace {
413 
414 // If there are more than 1K comma-delimited strings in target, remove
415 // the extra ones.
SanitizeTargetUri(absl::string_view target)416 std::string SanitizeTargetUri(absl::string_view target) {
417   constexpr size_t kMaxCommaDelimitedStrings = 1000;
418   std::vector<absl::string_view> parts = absl::StrSplit(target, ',');
419   if (parts.size() > kMaxCommaDelimitedStrings) {
420     parts.resize(kMaxCommaDelimitedStrings);
421   }
422   return absl::StrJoin(parts, ",");
423 }
424 
425 }  // namespace
426 
CreateChannel(const api_fuzzer::CreateChannel & create_channel)427 ApiFuzzer::Result ApiFuzzer::CreateChannel(
428     const api_fuzzer::CreateChannel& create_channel) {
429   if (channel_ != nullptr) return Result::kComplete;
430   // ExecCtx is needed for ChannelArgs destruction.
431   ExecCtx exec_ctx;
432   testing::FuzzingEnvironment fuzzing_env;
433   fuzzing_env.resource_quota = resource_quota();
434   ChannelArgs args = testing::CreateChannelArgsFromFuzzingConfiguration(
435       create_channel.channel_args(), fuzzing_env);
436   if (create_channel.inproc()) {
437     if (server_ == nullptr) return Result::kFailed;
438     channel_ = grpc_inproc_channel_create(server_, args.ToC().get(), nullptr);
439   } else {
440     grpc_channel_credentials* creds =
441         create_channel.has_channel_creds()
442             ? ReadChannelCreds(create_channel.channel_creds())
443             : grpc_insecure_credentials_create();
444     channel_ =
445         grpc_channel_create(SanitizeTargetUri(create_channel.target()).c_str(),
446                             creds, args.ToC().get());
447     grpc_channel_credentials_release(creds);
448   }
449   GPR_ASSERT(channel_ != nullptr);
450   channel_force_delete_ = false;
451   return Result::kComplete;
452 }
453 
CreateServer(const api_fuzzer::CreateServer & create_server)454 ApiFuzzer::Result ApiFuzzer::CreateServer(
455     const api_fuzzer::CreateServer& create_server) {
456   if (server_ == nullptr) {
457     // ExecCtx is needed for ChannelArgs destruction.
458     ExecCtx exec_ctx;
459     testing::FuzzingEnvironment fuzzing_env;
460     fuzzing_env.resource_quota = resource_quota();
461     ChannelArgs args = testing::CreateChannelArgsFromFuzzingConfiguration(
462         create_server.channel_args(), fuzzing_env);
463     server_ = grpc_server_create(args.ToC().get(), nullptr);
464     GPR_ASSERT(server_ != nullptr);
465     grpc_server_register_completion_queue(server_, cq(), nullptr);
466     for (const auto& http2_port : create_server.http2_ports()) {
467       auto* creds = ReadServerCreds(http2_port.server_creds());
468       auto addr = absl::StrCat("localhost:", http2_port.port());
469       grpc_server_add_http2_port(server_, addr.c_str(), creds);
470       grpc_server_credentials_release(creds);
471     }
472     grpc_server_start(server_);
473     ResetServerState();
474   } else {
475     return Result::kFailed;
476   }
477   return Result::kComplete;
478 }
479 
DestroyServer()480 void ApiFuzzer::DestroyServer() {
481   grpc_server_destroy(server_);
482   server_ = nullptr;
483 }
484 
DestroyChannel()485 void ApiFuzzer::DestroyChannel() {
486   grpc_channel_destroy(channel_);
487   channel_ = nullptr;
488 }
489 
490 }  // namespace testing
491 }  // namespace grpc_core
492 
493 using grpc_core::testing::ApiFuzzer;
494 
DEFINE_PROTO_FUZZER(const api_fuzzer::Msg & msg)495 DEFINE_PROTO_FUZZER(const api_fuzzer::Msg& msg) {
496   if (squelch && !grpc_core::GetEnv("GRPC_TRACE_FUZZER").has_value()) {
497     gpr_set_log_function(dont_log);
498   }
499   grpc_core::ApplyFuzzConfigVars(msg.config_vars());
500   grpc_core::TestOnlyReloadExperimentsFromConfigVariables();
501   ApiFuzzer(msg.event_engine_actions()).Run(msg.actions());
502 }
503