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