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