1ffb1132eSMatt Morehouse //===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
2ffb1132eSMatt Morehouse //
3ffb1132eSMatt Morehouse //                     The LLVM Compiler Infrastructure
4ffb1132eSMatt Morehouse //
5ffb1132eSMatt Morehouse // This file is distributed under the University of Illinois Open Source
6ffb1132eSMatt Morehouse // License. See LICENSE.TXT for details.
7ffb1132eSMatt Morehouse //
8ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===//
9ffb1132eSMatt Morehouse // Misc utils implementation using Fuchsia/Zircon APIs.
10ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===//
11ffb1132eSMatt Morehouse #include "FuzzerDefs.h"
12ffb1132eSMatt Morehouse 
13ffb1132eSMatt Morehouse #if LIBFUZZER_FUCHSIA
14ffb1132eSMatt Morehouse 
15ffb1132eSMatt Morehouse #include "FuzzerInternal.h"
16ffb1132eSMatt Morehouse #include "FuzzerUtil.h"
17ffb1132eSMatt Morehouse #include <cerrno>
18ffb1132eSMatt Morehouse #include <cinttypes>
19ffb1132eSMatt Morehouse #include <cstdint>
20ffb1132eSMatt Morehouse #include <fcntl.h>
21ffb1132eSMatt Morehouse #include <launchpad/launchpad.h>
22ffb1132eSMatt Morehouse #include <string>
23dd097445SPetr Hosek #include <sys/select.h>
24ffb1132eSMatt Morehouse #include <thread>
252f70693eSPetr Hosek #include <unistd.h>
26ffb1132eSMatt Morehouse #include <zircon/errors.h>
272f70693eSPetr Hosek #include <zircon/process.h>
28ffb1132eSMatt Morehouse #include <zircon/status.h>
29ffb1132eSMatt Morehouse #include <zircon/syscalls.h>
30ffb1132eSMatt Morehouse #include <zircon/syscalls/port.h>
31ffb1132eSMatt Morehouse #include <zircon/types.h>
32ffb1132eSMatt Morehouse 
33ffb1132eSMatt Morehouse namespace fuzzer {
34ffb1132eSMatt Morehouse 
35ffb1132eSMatt Morehouse namespace {
36ffb1132eSMatt Morehouse 
37ffb1132eSMatt Morehouse // A magic value for the Zircon exception port, chosen to spell 'FUZZING'
38ffb1132eSMatt Morehouse // when interpreted as a byte sequence on little-endian platforms.
39ffb1132eSMatt Morehouse const uint64_t kFuzzingCrash = 0x474e495a5a5546;
40ffb1132eSMatt Morehouse 
41ffb1132eSMatt Morehouse void AlarmHandler(int Seconds) {
42ffb1132eSMatt Morehouse   while (true) {
43ffb1132eSMatt Morehouse     SleepSeconds(Seconds);
44ffb1132eSMatt Morehouse     Fuzzer::StaticAlarmCallback();
45ffb1132eSMatt Morehouse   }
46ffb1132eSMatt Morehouse }
47ffb1132eSMatt Morehouse 
48ffb1132eSMatt Morehouse void InterruptHandler() {
497a31c7adSPetr Hosek   fd_set readfds;
50ffb1132eSMatt Morehouse   // Ctrl-C sends ETX in Zircon.
517a31c7adSPetr Hosek   do {
527a31c7adSPetr Hosek     FD_ZERO(&readfds);
537a31c7adSPetr Hosek     FD_SET(STDIN_FILENO, &readfds);
547a31c7adSPetr Hosek     select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr);
557a31c7adSPetr Hosek   } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03);
56ffb1132eSMatt Morehouse   Fuzzer::StaticInterruptCallback();
57ffb1132eSMatt Morehouse }
58ffb1132eSMatt Morehouse 
592f70693eSPetr Hosek void CrashHandler(zx_handle_t *Port) {
602f70693eSPetr Hosek   std::unique_ptr<zx_handle_t> ExceptionPort(Port);
61ffb1132eSMatt Morehouse   zx_port_packet_t Packet;
62*796bb7d4SPetr Hosek   _zx_port_wait(*ExceptionPort, ZX_TIME_INFINITE, &Packet);
63ffb1132eSMatt Morehouse   // Unbind as soon as possible so we don't receive exceptions from this thread.
642f70693eSPetr Hosek   if (_zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID,
65ffb1132eSMatt Morehouse                                    kFuzzingCrash, 0) != ZX_OK) {
66ffb1132eSMatt Morehouse     // Shouldn't happen; if it does the safest option is to just exit.
67ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to unbind exception port; aborting!\n");
68ffb1132eSMatt Morehouse     exit(1);
69ffb1132eSMatt Morehouse   }
70ffb1132eSMatt Morehouse   if (Packet.key != kFuzzingCrash) {
71ffb1132eSMatt Morehouse     Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n",
72ffb1132eSMatt Morehouse            Packet.key);
73ffb1132eSMatt Morehouse     exit(1);
74ffb1132eSMatt Morehouse   }
75ffb1132eSMatt Morehouse   // CrashCallback should not return from this call
76ffb1132eSMatt Morehouse   Fuzzer::StaticCrashSignalCallback();
77ffb1132eSMatt Morehouse }
78ffb1132eSMatt Morehouse 
79ffb1132eSMatt Morehouse } // namespace
80ffb1132eSMatt Morehouse 
81ffb1132eSMatt Morehouse // Platform specific functions.
82ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) {
83ffb1132eSMatt Morehouse   zx_status_t rc;
84ffb1132eSMatt Morehouse 
85ffb1132eSMatt Morehouse   // Set up alarm handler if needed.
86ffb1132eSMatt Morehouse   if (Options.UnitTimeoutSec > 0) {
87ffb1132eSMatt Morehouse     std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
88ffb1132eSMatt Morehouse     T.detach();
89ffb1132eSMatt Morehouse   }
90ffb1132eSMatt Morehouse 
91ffb1132eSMatt Morehouse   // Set up interrupt handler if needed.
92ffb1132eSMatt Morehouse   if (Options.HandleInt || Options.HandleTerm) {
93ffb1132eSMatt Morehouse     std::thread T(InterruptHandler);
94ffb1132eSMatt Morehouse     T.detach();
95ffb1132eSMatt Morehouse   }
96ffb1132eSMatt Morehouse 
97ffb1132eSMatt Morehouse   // Early exit if no crash handler needed.
98ffb1132eSMatt Morehouse   if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
99ffb1132eSMatt Morehouse       !Options.HandleFpe && !Options.HandleAbrt)
100ffb1132eSMatt Morehouse     return;
101ffb1132eSMatt Morehouse 
102ffb1132eSMatt Morehouse   // Create an exception port
1032f70693eSPetr Hosek   zx_handle_t *ExceptionPort = new zx_handle_t;
1042f70693eSPetr Hosek   if ((rc = _zx_port_create(0, ExceptionPort)) != ZX_OK) {
1052f70693eSPetr Hosek     Printf("libFuzzer: zx_port_create failed: %s\n", _zx_status_get_string(rc));
106ffb1132eSMatt Morehouse     exit(1);
107ffb1132eSMatt Morehouse   }
108ffb1132eSMatt Morehouse 
109ffb1132eSMatt Morehouse   // Bind the port to receive exceptions from our process
1102f70693eSPetr Hosek   if ((rc = _zx_task_bind_exception_port(_zx_process_self(), *ExceptionPort,
111ffb1132eSMatt Morehouse                                          kFuzzingCrash, 0)) != ZX_OK) {
112ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to bind exception port: %s\n",
113*796bb7d4SPetr Hosek            _zx_status_get_string(rc));
114ffb1132eSMatt Morehouse     exit(1);
115ffb1132eSMatt Morehouse   }
116ffb1132eSMatt Morehouse 
117ffb1132eSMatt Morehouse   // Set up the crash handler.
118ffb1132eSMatt Morehouse   std::thread T(CrashHandler, ExceptionPort);
119ffb1132eSMatt Morehouse   T.detach();
120ffb1132eSMatt Morehouse }
121ffb1132eSMatt Morehouse 
122ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) {
1232f70693eSPetr Hosek   _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
124ffb1132eSMatt Morehouse }
125ffb1132eSMatt Morehouse 
126ffb1132eSMatt Morehouse unsigned long GetPid() {
127ffb1132eSMatt Morehouse   zx_status_t rc;
128ffb1132eSMatt Morehouse   zx_info_handle_basic_t Info;
129*796bb7d4SPetr Hosek   if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
130ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
131ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
132*796bb7d4SPetr Hosek            _zx_status_get_string(rc));
133ffb1132eSMatt Morehouse     exit(1);
134ffb1132eSMatt Morehouse   }
135ffb1132eSMatt Morehouse   return Info.koid;
136ffb1132eSMatt Morehouse }
137ffb1132eSMatt Morehouse 
138ffb1132eSMatt Morehouse size_t GetPeakRSSMb() {
139ffb1132eSMatt Morehouse   zx_status_t rc;
140ffb1132eSMatt Morehouse   zx_info_task_stats_t Info;
1412f70693eSPetr Hosek   if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
142ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
143ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
1442f70693eSPetr Hosek            _zx_status_get_string(rc));
145ffb1132eSMatt Morehouse     exit(1);
146ffb1132eSMatt Morehouse   }
147ffb1132eSMatt Morehouse   return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
148ffb1132eSMatt Morehouse }
149ffb1132eSMatt Morehouse 
1502f70693eSPetr Hosek template <typename Fn>
1512f70693eSPetr Hosek class RunOnDestruction {
1522f70693eSPetr Hosek  public:
1532f70693eSPetr Hosek   explicit RunOnDestruction(Fn fn) : fn_(fn) {}
1542f70693eSPetr Hosek   ~RunOnDestruction() { fn_(); }
1552f70693eSPetr Hosek 
1562f70693eSPetr Hosek  private:
1572f70693eSPetr Hosek   Fn fn_;
1582f70693eSPetr Hosek };
1592f70693eSPetr Hosek 
1602f70693eSPetr Hosek template <typename Fn>
1612f70693eSPetr Hosek RunOnDestruction<Fn> at_scope_exit(Fn fn) {
1622f70693eSPetr Hosek   return RunOnDestruction<Fn>(fn);
1632f70693eSPetr Hosek }
1642f70693eSPetr Hosek 
165ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) {
166ffb1132eSMatt Morehouse   zx_status_t rc;
167ffb1132eSMatt Morehouse 
168ffb1132eSMatt Morehouse   // Convert arguments to C array
169ffb1132eSMatt Morehouse   auto Args = Cmd.getArguments();
170ffb1132eSMatt Morehouse   size_t Argc = Args.size();
171ffb1132eSMatt Morehouse   assert(Argc != 0);
172ffb1132eSMatt Morehouse   std::unique_ptr<const char *[]> Argv(new const char *[Argc]);
173ffb1132eSMatt Morehouse   for (size_t i = 0; i < Argc; ++i)
174ffb1132eSMatt Morehouse     Argv[i] = Args[i].c_str();
175ffb1132eSMatt Morehouse 
176ffb1132eSMatt Morehouse   // Create the basic launchpad.  Clone everything except stdio.
177ffb1132eSMatt Morehouse   launchpad_t *lp;
178ffb1132eSMatt Morehouse   launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp);
179ffb1132eSMatt Morehouse   launchpad_load_from_file(lp, Argv[0]);
180ffb1132eSMatt Morehouse   launchpad_set_args(lp, Argc, Argv.get());
181ffb1132eSMatt Morehouse   launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO));
182ffb1132eSMatt Morehouse 
183ffb1132eSMatt Morehouse   // Determine stdout
184ffb1132eSMatt Morehouse   int FdOut = STDOUT_FILENO;
1852f70693eSPetr Hosek 
186ffb1132eSMatt Morehouse   if (Cmd.hasOutputFile()) {
187ffb1132eSMatt Morehouse     auto Filename = Cmd.getOutputFile();
1882f70693eSPetr Hosek     FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
1892f70693eSPetr Hosek     if (FdOut == -1) {
190ffb1132eSMatt Morehouse       Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
191ffb1132eSMatt Morehouse              strerror(errno));
192ffb1132eSMatt Morehouse       return ZX_ERR_IO;
193ffb1132eSMatt Morehouse     }
194ffb1132eSMatt Morehouse   }
1952f70693eSPetr Hosek   auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );
196ffb1132eSMatt Morehouse 
197ffb1132eSMatt Morehouse   // Determine stderr
198ffb1132eSMatt Morehouse   int FdErr = STDERR_FILENO;
199ffb1132eSMatt Morehouse   if (Cmd.isOutAndErrCombined())
200ffb1132eSMatt Morehouse     FdErr = FdOut;
201ffb1132eSMatt Morehouse 
202ffb1132eSMatt Morehouse   // Clone the file descriptors into the new process
203ffb1132eSMatt Morehouse   if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK ||
204ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK ||
205ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) {
2062f70693eSPetr Hosek     Printf("libFuzzer: failed to clone FDIO: %s\n", _zx_status_get_string(rc));
207ffb1132eSMatt Morehouse     return rc;
208ffb1132eSMatt Morehouse   }
209ffb1132eSMatt Morehouse 
210ffb1132eSMatt Morehouse   // Start the process
211ffb1132eSMatt Morehouse   zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
212ffb1132eSMatt Morehouse   const char *ErrorMsg = nullptr;
213ffb1132eSMatt Morehouse   if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) {
214ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
2152f70693eSPetr Hosek            _zx_status_get_string(rc));
216ffb1132eSMatt Morehouse     return rc;
217ffb1132eSMatt Morehouse   }
2182f70693eSPetr Hosek   auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
219ffb1132eSMatt Morehouse 
220ffb1132eSMatt Morehouse   // Now join the process and return the exit status.
2212f70693eSPetr Hosek   if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
2222f70693eSPetr Hosek                                 ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
223ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
2242f70693eSPetr Hosek            _zx_status_get_string(rc));
225ffb1132eSMatt Morehouse     return rc;
226ffb1132eSMatt Morehouse   }
227ffb1132eSMatt Morehouse 
228ffb1132eSMatt Morehouse   zx_info_process_t Info;
2292f70693eSPetr Hosek   if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
2302f70693eSPetr Hosek                                 sizeof(Info), nullptr, nullptr)) != ZX_OK) {
231ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
232*796bb7d4SPetr Hosek            _zx_status_get_string(rc));
233ffb1132eSMatt Morehouse     return rc;
234ffb1132eSMatt Morehouse   }
235ffb1132eSMatt Morehouse 
236ffb1132eSMatt Morehouse   return Info.return_code;
237ffb1132eSMatt Morehouse }
238ffb1132eSMatt Morehouse 
239ffb1132eSMatt Morehouse const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
240ffb1132eSMatt Morehouse                          size_t PattLen) {
241ffb1132eSMatt Morehouse   return memmem(Data, DataLen, Patt, PattLen);
242ffb1132eSMatt Morehouse }
243ffb1132eSMatt Morehouse 
244ffb1132eSMatt Morehouse } // namespace fuzzer
245ffb1132eSMatt Morehouse 
246ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA
247