|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef LIB_FIDL_CPP_FUZZING_FUZZER_H_ | 
|  | #define LIB_FIDL_CPP_FUZZING_FUZZER_H_ | 
|  |  | 
|  | #include <lib/async/dispatcher.h> | 
|  | #include <lib/fidl/cpp/interface_ptr.h> | 
|  | #include <lib/zx/clock.h> | 
|  | #include <lib/zx/event.h> | 
|  | #include <lib/zx/time.h> | 
|  | #include <zircon/syscalls.h> | 
|  | #include <zircon/types.h> | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | extern "C" { | 
|  | #endif | 
|  |  | 
|  | zx_status_t fuzzer_init(); | 
|  | zx_status_t fuzzer_connect(zx_handle_t, async_dispatcher_t*); | 
|  | zx_status_t fuzzer_disconnect(zx_handle_t, async_dispatcher_t*); | 
|  | zx_status_t fuzzer_clean_up(); | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | } | 
|  | #endif | 
|  |  | 
|  | namespace fidl { | 
|  | namespace fuzzing { | 
|  |  | 
|  | // Helper class for signalling when a callback completes. | 
|  | // | 
|  | // Use `zx::unowned_event` because `Fuzzer` that owns the event may go out of scope before callback | 
|  | // is invoked. | 
|  | class FuzzerCallbackSignaller { | 
|  | public: | 
|  | explicit FuzzerCallbackSignaller(const zx::event& evt) : evt_(evt) {} | 
|  |  | 
|  | // Invoked from within method callback to signal that callback has run. Note that `signal()` may | 
|  | // return non-OK status if, for example, fuzzer timed out waiting for callback. | 
|  | zx_status_t SignalCallback() const { return evt_->signal(0, ZX_USER_SIGNAL_7); } | 
|  |  | 
|  | private: | 
|  | zx::unowned_event evt_; | 
|  | }; | 
|  |  | 
|  | // Helper class for code generated by the `cpp_libfuzzer` FIDL compiler backend. | 
|  | // | 
|  | // This class implements setup, bind, and teardown for a single pass of a fuzzer generated using the | 
|  | // `cpp_libfuzzer` FIDL compiler backend. It _always_ owns `evt_` handle. It _sometimes_ owns the | 
|  | // `client_handle_` and `service_handle_`; these are stored as raw handles because one of them is | 
|  | // passed to an opaque service provider via a C interface. | 
|  | template <typename Impl> | 
|  | class Fuzzer { | 
|  | public: | 
|  | Fuzzer(async_dispatcher_t* dispatcher) | 
|  | : init_status_(ZX_ERR_UNAVAILABLE), | 
|  | service_status_(ZX_ERR_UNAVAILABLE), | 
|  | client_status_(ZX_ERR_UNAVAILABLE), | 
|  | service_handle_(ZX_HANDLE_INVALID), | 
|  | client_handle_(ZX_HANDLE_INVALID), | 
|  | dispatcher_(dispatcher) {} | 
|  |  | 
|  | // Attempt to initialize the fuzzer by allowing the service provider to initialize itself and | 
|  | // creating kernel primitives. | 
|  | zx_status_t Init() { | 
|  | if ((init_status_ = fuzzer_init()) != ZX_OK) { | 
|  | return init_status_; | 
|  | } | 
|  | if ((init_status_ = zx_channel_create(0, &service_handle_, &client_handle_)) != ZX_OK) { | 
|  | return init_status_; | 
|  | } | 
|  | if ((init_status_ = zx::event::create(0, &evt_)) != ZX_OK) { | 
|  | return init_status_; | 
|  | } | 
|  |  | 
|  | return init_status_; | 
|  | } | 
|  |  | 
|  | // Attempt to pass `service_handle_` to service provider. If successful, the service | 
|  | // implementation now owns `service_handle_`. | 
|  | zx_status_t BindService() { | 
|  | service_status_ = fuzzer_connect(service_handle_, dispatcher_); | 
|  | return service_status_; | 
|  | } | 
|  |  | 
|  | // Attempt to initialize client `InterfacePtr`. If successful, the `InterfacePtr` now owns | 
|  | // `client_handle_`. | 
|  | zx_status_t BindClient(InterfacePtr<Impl>* iface, async_dispatcher_t* dispatcher) { | 
|  | zx::channel client_channel(client_handle_); | 
|  | client_status_ = iface->Bind(std::move(client_channel), dispatcher); | 
|  | return client_status_; | 
|  | } | 
|  |  | 
|  | // Produce a callback signaller that may outlive this Fuzzer. | 
|  | FuzzerCallbackSignaller NewCallbackSignaller() { return FuzzerCallbackSignaller(evt_); } | 
|  |  | 
|  | // Invoked from main fuzzer thread to wait for callback to run. | 
|  | // TODO(markdittmer): Make deadline configurable. | 
|  | zx_status_t WaitForCallback() const { | 
|  | zx_signals_t pending; | 
|  | zx::time deadline = zx::clock::get_monotonic() + zx::duration(5000000000); | 
|  | return evt_.wait_one(ZX_USER_SIGNAL_7, deadline, &pending); | 
|  | } | 
|  |  | 
|  | ~Fuzzer() { | 
|  | // Fuzzer owns client_handle_ when client setup failed. | 
|  | if (client_status_ != ZX_OK) { | 
|  | zx_handle_close(client_handle_); | 
|  | } | 
|  |  | 
|  | // Service owns service_handle_ when service setup succeeded, else Fuzzer owns it. | 
|  | if (service_status_ == ZX_OK) { | 
|  | fuzzer_disconnect(service_handle_, dispatcher_); | 
|  | } else { | 
|  | zx_handle_close(service_handle_); | 
|  | } | 
|  |  | 
|  | // Clean up only when init succeeded. | 
|  | if (init_status_ == ZX_OK) { | 
|  | fuzzer_clean_up(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | zx_status_t init_status_; | 
|  | zx_status_t service_status_; | 
|  | zx_status_t client_status_; | 
|  | zx_handle_t service_handle_; | 
|  | zx_handle_t client_handle_; | 
|  | zx::event evt_; | 
|  | async_dispatcher_t* dispatcher_; | 
|  | }; | 
|  |  | 
|  | }  // namespace fuzzing | 
|  | }  // namespace fidl | 
|  |  | 
|  | #endif  // LIB_FIDL_CPP_FUZZING_FUZZER_H_ |