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>
23ffb1132eSMatt Morehouse #include <thread>
242f70693eSPetr Hosek #include <unistd.h>
25ffb1132eSMatt Morehouse #include <zircon/errors.h>
262f70693eSPetr Hosek #include <zircon/process.h>
27ffb1132eSMatt Morehouse #include <zircon/status.h>
28ffb1132eSMatt Morehouse #include <zircon/syscalls.h>
29ffb1132eSMatt Morehouse #include <zircon/syscalls/port.h>
30ffb1132eSMatt Morehouse #include <zircon/types.h>
31ffb1132eSMatt Morehouse 
32ffb1132eSMatt Morehouse namespace fuzzer {
33ffb1132eSMatt Morehouse 
34ffb1132eSMatt Morehouse namespace {
35ffb1132eSMatt Morehouse 
36ffb1132eSMatt Morehouse // A magic value for the Zircon exception port, chosen to spell 'FUZZING'
37ffb1132eSMatt Morehouse // when interpreted as a byte sequence on little-endian platforms.
38ffb1132eSMatt Morehouse const uint64_t kFuzzingCrash = 0x474e495a5a5546;
39ffb1132eSMatt Morehouse 
40ffb1132eSMatt Morehouse void AlarmHandler(int Seconds) {
41ffb1132eSMatt Morehouse   while (true) {
42ffb1132eSMatt Morehouse     SleepSeconds(Seconds);
43ffb1132eSMatt Morehouse     Fuzzer::StaticAlarmCallback();
44ffb1132eSMatt Morehouse   }
45ffb1132eSMatt Morehouse }
46ffb1132eSMatt Morehouse 
47ffb1132eSMatt Morehouse void InterruptHandler() {
48*7a31c7adSPetr Hosek   fd_set readfds;
49ffb1132eSMatt Morehouse   // Ctrl-C sends ETX in Zircon.
50*7a31c7adSPetr Hosek   do {
51*7a31c7adSPetr Hosek     FD_ZERO(&readfds);
52*7a31c7adSPetr Hosek     FD_SET(STDIN_FILENO, &readfds);
53*7a31c7adSPetr Hosek     select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr);
54*7a31c7adSPetr Hosek   } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03);
55ffb1132eSMatt Morehouse   Fuzzer::StaticInterruptCallback();
56ffb1132eSMatt Morehouse }
57ffb1132eSMatt Morehouse 
582f70693eSPetr Hosek void CrashHandler(zx_handle_t *Port) {
592f70693eSPetr Hosek   std::unique_ptr<zx_handle_t> ExceptionPort(Port);
60ffb1132eSMatt Morehouse   zx_port_packet_t Packet;
612f70693eSPetr Hosek   _zx_port_wait(*ExceptionPort, ZX_TIME_INFINITE, &Packet, 1);
62ffb1132eSMatt Morehouse   // Unbind as soon as possible so we don't receive exceptions from this thread.
632f70693eSPetr Hosek   if (_zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID,
64ffb1132eSMatt Morehouse                                    kFuzzingCrash, 0) != ZX_OK) {
65ffb1132eSMatt Morehouse     // Shouldn't happen; if it does the safest option is to just exit.
66ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to unbind exception port; aborting!\n");
67ffb1132eSMatt Morehouse     exit(1);
68ffb1132eSMatt Morehouse   }
69ffb1132eSMatt Morehouse   if (Packet.key != kFuzzingCrash) {
70ffb1132eSMatt Morehouse     Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n",
71ffb1132eSMatt Morehouse            Packet.key);
72ffb1132eSMatt Morehouse     exit(1);
73ffb1132eSMatt Morehouse   }
74ffb1132eSMatt Morehouse   // CrashCallback should not return from this call
75ffb1132eSMatt Morehouse   Fuzzer::StaticCrashSignalCallback();
76ffb1132eSMatt Morehouse }
77ffb1132eSMatt Morehouse 
78ffb1132eSMatt Morehouse } // namespace
79ffb1132eSMatt Morehouse 
80ffb1132eSMatt Morehouse // Platform specific functions.
81ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) {
82ffb1132eSMatt Morehouse   zx_status_t rc;
83ffb1132eSMatt Morehouse 
84ffb1132eSMatt Morehouse   // Set up alarm handler if needed.
85ffb1132eSMatt Morehouse   if (Options.UnitTimeoutSec > 0) {
86ffb1132eSMatt Morehouse     std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
87ffb1132eSMatt Morehouse     T.detach();
88ffb1132eSMatt Morehouse   }
89ffb1132eSMatt Morehouse 
90ffb1132eSMatt Morehouse   // Set up interrupt handler if needed.
91ffb1132eSMatt Morehouse   if (Options.HandleInt || Options.HandleTerm) {
92ffb1132eSMatt Morehouse     std::thread T(InterruptHandler);
93ffb1132eSMatt Morehouse     T.detach();
94ffb1132eSMatt Morehouse   }
95ffb1132eSMatt Morehouse 
96ffb1132eSMatt Morehouse   // Early exit if no crash handler needed.
97ffb1132eSMatt Morehouse   if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
98ffb1132eSMatt Morehouse       !Options.HandleFpe && !Options.HandleAbrt)
99ffb1132eSMatt Morehouse     return;
100ffb1132eSMatt Morehouse 
101ffb1132eSMatt Morehouse   // Create an exception port
1022f70693eSPetr Hosek   zx_handle_t *ExceptionPort = new zx_handle_t;
1032f70693eSPetr Hosek   if ((rc = _zx_port_create(0, ExceptionPort)) != ZX_OK) {
1042f70693eSPetr Hosek     Printf("libFuzzer: zx_port_create failed: %s\n", _zx_status_get_string(rc));
105ffb1132eSMatt Morehouse     exit(1);
106ffb1132eSMatt Morehouse   }
107ffb1132eSMatt Morehouse 
108ffb1132eSMatt Morehouse   // Bind the port to receive exceptions from our process
1092f70693eSPetr Hosek   if ((rc = _zx_task_bind_exception_port(_zx_process_self(), *ExceptionPort,
110ffb1132eSMatt Morehouse                                          kFuzzingCrash, 0)) != ZX_OK) {
111ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to bind exception port: %s\n",
112ffb1132eSMatt Morehouse            zx_status_get_string(rc));
113ffb1132eSMatt Morehouse     exit(1);
114ffb1132eSMatt Morehouse   }
115ffb1132eSMatt Morehouse 
116ffb1132eSMatt Morehouse   // Set up the crash handler.
117ffb1132eSMatt Morehouse   std::thread T(CrashHandler, ExceptionPort);
118ffb1132eSMatt Morehouse   T.detach();
119ffb1132eSMatt Morehouse }
120ffb1132eSMatt Morehouse 
121ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) {
1222f70693eSPetr Hosek   _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
123ffb1132eSMatt Morehouse }
124ffb1132eSMatt Morehouse 
125ffb1132eSMatt Morehouse unsigned long GetPid() {
126ffb1132eSMatt Morehouse   zx_status_t rc;
127ffb1132eSMatt Morehouse   zx_info_handle_basic_t Info;
1282f70693eSPetr Hosek   if ((rc = zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
129ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
130ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
131ffb1132eSMatt Morehouse            zx_status_get_string(rc));
132ffb1132eSMatt Morehouse     exit(1);
133ffb1132eSMatt Morehouse   }
134ffb1132eSMatt Morehouse   return Info.koid;
135ffb1132eSMatt Morehouse }
136ffb1132eSMatt Morehouse 
137ffb1132eSMatt Morehouse size_t GetPeakRSSMb() {
138ffb1132eSMatt Morehouse   zx_status_t rc;
139ffb1132eSMatt Morehouse   zx_info_task_stats_t Info;
1402f70693eSPetr Hosek   if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
141ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
142ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
1432f70693eSPetr Hosek            _zx_status_get_string(rc));
144ffb1132eSMatt Morehouse     exit(1);
145ffb1132eSMatt Morehouse   }
146ffb1132eSMatt Morehouse   return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
147ffb1132eSMatt Morehouse }
148ffb1132eSMatt Morehouse 
1492f70693eSPetr Hosek template <typename Fn>
1502f70693eSPetr Hosek class RunOnDestruction {
1512f70693eSPetr Hosek  public:
1522f70693eSPetr Hosek   explicit RunOnDestruction(Fn fn) : fn_(fn) {}
1532f70693eSPetr Hosek   ~RunOnDestruction() { fn_(); }
1542f70693eSPetr Hosek 
1552f70693eSPetr Hosek  private:
1562f70693eSPetr Hosek   Fn fn_;
1572f70693eSPetr Hosek };
1582f70693eSPetr Hosek 
1592f70693eSPetr Hosek template <typename Fn>
1602f70693eSPetr Hosek RunOnDestruction<Fn> at_scope_exit(Fn fn) {
1612f70693eSPetr Hosek   return RunOnDestruction<Fn>(fn);
1622f70693eSPetr Hosek }
1632f70693eSPetr Hosek 
164ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) {
165ffb1132eSMatt Morehouse   zx_status_t rc;
166ffb1132eSMatt Morehouse 
167ffb1132eSMatt Morehouse   // Convert arguments to C array
168ffb1132eSMatt Morehouse   auto Args = Cmd.getArguments();
169ffb1132eSMatt Morehouse   size_t Argc = Args.size();
170ffb1132eSMatt Morehouse   assert(Argc != 0);
171ffb1132eSMatt Morehouse   std::unique_ptr<const char *[]> Argv(new const char *[Argc]);
172ffb1132eSMatt Morehouse   for (size_t i = 0; i < Argc; ++i)
173ffb1132eSMatt Morehouse     Argv[i] = Args[i].c_str();
174ffb1132eSMatt Morehouse 
175ffb1132eSMatt Morehouse   // Create the basic launchpad.  Clone everything except stdio.
176ffb1132eSMatt Morehouse   launchpad_t *lp;
177ffb1132eSMatt Morehouse   launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp);
178ffb1132eSMatt Morehouse   launchpad_load_from_file(lp, Argv[0]);
179ffb1132eSMatt Morehouse   launchpad_set_args(lp, Argc, Argv.get());
180ffb1132eSMatt Morehouse   launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO));
181ffb1132eSMatt Morehouse 
182ffb1132eSMatt Morehouse   // Determine stdout
183ffb1132eSMatt Morehouse   int FdOut = STDOUT_FILENO;
1842f70693eSPetr Hosek 
185ffb1132eSMatt Morehouse   if (Cmd.hasOutputFile()) {
186ffb1132eSMatt Morehouse     auto Filename = Cmd.getOutputFile();
1872f70693eSPetr Hosek     FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
1882f70693eSPetr Hosek     if (FdOut == -1) {
189ffb1132eSMatt Morehouse       Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
190ffb1132eSMatt Morehouse              strerror(errno));
191ffb1132eSMatt Morehouse       return ZX_ERR_IO;
192ffb1132eSMatt Morehouse     }
193ffb1132eSMatt Morehouse   }
1942f70693eSPetr Hosek   auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );
195ffb1132eSMatt Morehouse 
196ffb1132eSMatt Morehouse   // Determine stderr
197ffb1132eSMatt Morehouse   int FdErr = STDERR_FILENO;
198ffb1132eSMatt Morehouse   if (Cmd.isOutAndErrCombined())
199ffb1132eSMatt Morehouse     FdErr = FdOut;
200ffb1132eSMatt Morehouse 
201ffb1132eSMatt Morehouse   // Clone the file descriptors into the new process
202ffb1132eSMatt Morehouse   if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK ||
203ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK ||
204ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) {
2052f70693eSPetr Hosek     Printf("libFuzzer: failed to clone FDIO: %s\n", _zx_status_get_string(rc));
206ffb1132eSMatt Morehouse     return rc;
207ffb1132eSMatt Morehouse   }
208ffb1132eSMatt Morehouse 
209ffb1132eSMatt Morehouse   // Start the process
210ffb1132eSMatt Morehouse   zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
211ffb1132eSMatt Morehouse   const char *ErrorMsg = nullptr;
212ffb1132eSMatt Morehouse   if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) {
213ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
2142f70693eSPetr Hosek            _zx_status_get_string(rc));
215ffb1132eSMatt Morehouse     return rc;
216ffb1132eSMatt Morehouse   }
2172f70693eSPetr Hosek   auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
218ffb1132eSMatt Morehouse 
219ffb1132eSMatt Morehouse   // Now join the process and return the exit status.
2202f70693eSPetr Hosek   if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
2212f70693eSPetr Hosek                                 ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
222ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
2232f70693eSPetr Hosek            _zx_status_get_string(rc));
224ffb1132eSMatt Morehouse     return rc;
225ffb1132eSMatt Morehouse   }
226ffb1132eSMatt Morehouse 
227ffb1132eSMatt Morehouse   zx_info_process_t Info;
2282f70693eSPetr Hosek   if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
2292f70693eSPetr Hosek                                 sizeof(Info), nullptr, nullptr)) != ZX_OK) {
230ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
231ffb1132eSMatt Morehouse            zx_status_get_string(rc));
232ffb1132eSMatt Morehouse     return rc;
233ffb1132eSMatt Morehouse   }
234ffb1132eSMatt Morehouse 
235ffb1132eSMatt Morehouse   return Info.return_code;
236ffb1132eSMatt Morehouse }
237ffb1132eSMatt Morehouse 
238ffb1132eSMatt Morehouse const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
239ffb1132eSMatt Morehouse                          size_t PattLen) {
240ffb1132eSMatt Morehouse   return memmem(Data, DataLen, Patt, PattLen);
241ffb1132eSMatt Morehouse }
242ffb1132eSMatt Morehouse 
243ffb1132eSMatt Morehouse } // namespace fuzzer
244ffb1132eSMatt Morehouse 
245ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA
246