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>
24*2f70693eSPetr Hosek #include <unistd.h>
25ffb1132eSMatt Morehouse #include <zircon/errors.h>
26*2f70693eSPetr 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() {
48ffb1132eSMatt Morehouse   // Ctrl-C sends ETX in Zircon.
49ffb1132eSMatt Morehouse   while (getchar() != 0x03);
50ffb1132eSMatt Morehouse   Fuzzer::StaticInterruptCallback();
51ffb1132eSMatt Morehouse }
52ffb1132eSMatt Morehouse 
53*2f70693eSPetr Hosek void CrashHandler(zx_handle_t *Port) {
54*2f70693eSPetr Hosek   std::unique_ptr<zx_handle_t> ExceptionPort(Port);
55ffb1132eSMatt Morehouse   zx_port_packet_t Packet;
56*2f70693eSPetr Hosek   _zx_port_wait(*ExceptionPort, ZX_TIME_INFINITE, &Packet, 1);
57ffb1132eSMatt Morehouse   // Unbind as soon as possible so we don't receive exceptions from this thread.
58*2f70693eSPetr Hosek   if (_zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID,
59ffb1132eSMatt Morehouse                                    kFuzzingCrash, 0) != ZX_OK) {
60ffb1132eSMatt Morehouse     // Shouldn't happen; if it does the safest option is to just exit.
61ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to unbind exception port; aborting!\n");
62ffb1132eSMatt Morehouse     exit(1);
63ffb1132eSMatt Morehouse   }
64ffb1132eSMatt Morehouse   if (Packet.key != kFuzzingCrash) {
65ffb1132eSMatt Morehouse     Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n",
66ffb1132eSMatt Morehouse            Packet.key);
67ffb1132eSMatt Morehouse     exit(1);
68ffb1132eSMatt Morehouse   }
69ffb1132eSMatt Morehouse   // CrashCallback should not return from this call
70ffb1132eSMatt Morehouse   Fuzzer::StaticCrashSignalCallback();
71ffb1132eSMatt Morehouse }
72ffb1132eSMatt Morehouse 
73ffb1132eSMatt Morehouse } // namespace
74ffb1132eSMatt Morehouse 
75ffb1132eSMatt Morehouse // Platform specific functions.
76ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) {
77ffb1132eSMatt Morehouse   zx_status_t rc;
78ffb1132eSMatt Morehouse 
79ffb1132eSMatt Morehouse   // Set up alarm handler if needed.
80ffb1132eSMatt Morehouse   if (Options.UnitTimeoutSec > 0) {
81ffb1132eSMatt Morehouse     std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
82ffb1132eSMatt Morehouse     T.detach();
83ffb1132eSMatt Morehouse   }
84ffb1132eSMatt Morehouse 
85ffb1132eSMatt Morehouse   // Set up interrupt handler if needed.
86ffb1132eSMatt Morehouse   if (Options.HandleInt || Options.HandleTerm) {
87ffb1132eSMatt Morehouse     std::thread T(InterruptHandler);
88ffb1132eSMatt Morehouse     T.detach();
89ffb1132eSMatt Morehouse   }
90ffb1132eSMatt Morehouse 
91ffb1132eSMatt Morehouse   // Early exit if no crash handler needed.
92ffb1132eSMatt Morehouse   if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
93ffb1132eSMatt Morehouse       !Options.HandleFpe && !Options.HandleAbrt)
94ffb1132eSMatt Morehouse     return;
95ffb1132eSMatt Morehouse 
96ffb1132eSMatt Morehouse   // Create an exception port
97*2f70693eSPetr Hosek   zx_handle_t *ExceptionPort = new zx_handle_t;
98*2f70693eSPetr Hosek   if ((rc = _zx_port_create(0, ExceptionPort)) != ZX_OK) {
99*2f70693eSPetr Hosek     Printf("libFuzzer: zx_port_create failed: %s\n", _zx_status_get_string(rc));
100ffb1132eSMatt Morehouse     exit(1);
101ffb1132eSMatt Morehouse   }
102ffb1132eSMatt Morehouse 
103ffb1132eSMatt Morehouse   // Bind the port to receive exceptions from our process
104*2f70693eSPetr Hosek   if ((rc = _zx_task_bind_exception_port(_zx_process_self(), *ExceptionPort,
105ffb1132eSMatt Morehouse                                          kFuzzingCrash, 0)) != ZX_OK) {
106ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to bind exception port: %s\n",
107ffb1132eSMatt Morehouse            zx_status_get_string(rc));
108ffb1132eSMatt Morehouse     exit(1);
109ffb1132eSMatt Morehouse   }
110ffb1132eSMatt Morehouse 
111ffb1132eSMatt Morehouse   // Set up the crash handler.
112ffb1132eSMatt Morehouse   std::thread T(CrashHandler, ExceptionPort);
113ffb1132eSMatt Morehouse   T.detach();
114ffb1132eSMatt Morehouse }
115ffb1132eSMatt Morehouse 
116ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) {
117*2f70693eSPetr Hosek   _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
118ffb1132eSMatt Morehouse }
119ffb1132eSMatt Morehouse 
120ffb1132eSMatt Morehouse unsigned long GetPid() {
121ffb1132eSMatt Morehouse   zx_status_t rc;
122ffb1132eSMatt Morehouse   zx_info_handle_basic_t Info;
123*2f70693eSPetr Hosek   if ((rc = zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
124ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
125ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
126ffb1132eSMatt Morehouse            zx_status_get_string(rc));
127ffb1132eSMatt Morehouse     exit(1);
128ffb1132eSMatt Morehouse   }
129ffb1132eSMatt Morehouse   return Info.koid;
130ffb1132eSMatt Morehouse }
131ffb1132eSMatt Morehouse 
132ffb1132eSMatt Morehouse size_t GetPeakRSSMb() {
133ffb1132eSMatt Morehouse   zx_status_t rc;
134ffb1132eSMatt Morehouse   zx_info_task_stats_t Info;
135*2f70693eSPetr Hosek   if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
136ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
137ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
138*2f70693eSPetr Hosek            _zx_status_get_string(rc));
139ffb1132eSMatt Morehouse     exit(1);
140ffb1132eSMatt Morehouse   }
141ffb1132eSMatt Morehouse   return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
142ffb1132eSMatt Morehouse }
143ffb1132eSMatt Morehouse 
144*2f70693eSPetr Hosek template <typename Fn>
145*2f70693eSPetr Hosek class RunOnDestruction {
146*2f70693eSPetr Hosek  public:
147*2f70693eSPetr Hosek   explicit RunOnDestruction(Fn fn) : fn_(fn) {}
148*2f70693eSPetr Hosek   ~RunOnDestruction() { fn_(); }
149*2f70693eSPetr Hosek 
150*2f70693eSPetr Hosek  private:
151*2f70693eSPetr Hosek   Fn fn_;
152*2f70693eSPetr Hosek };
153*2f70693eSPetr Hosek 
154*2f70693eSPetr Hosek template <typename Fn>
155*2f70693eSPetr Hosek RunOnDestruction<Fn> at_scope_exit(Fn fn) {
156*2f70693eSPetr Hosek   return RunOnDestruction<Fn>(fn);
157*2f70693eSPetr Hosek }
158*2f70693eSPetr Hosek 
159ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) {
160ffb1132eSMatt Morehouse   zx_status_t rc;
161ffb1132eSMatt Morehouse 
162ffb1132eSMatt Morehouse   // Convert arguments to C array
163ffb1132eSMatt Morehouse   auto Args = Cmd.getArguments();
164ffb1132eSMatt Morehouse   size_t Argc = Args.size();
165ffb1132eSMatt Morehouse   assert(Argc != 0);
166ffb1132eSMatt Morehouse   std::unique_ptr<const char *[]> Argv(new const char *[Argc]);
167ffb1132eSMatt Morehouse   for (size_t i = 0; i < Argc; ++i)
168ffb1132eSMatt Morehouse     Argv[i] = Args[i].c_str();
169ffb1132eSMatt Morehouse 
170ffb1132eSMatt Morehouse   // Create the basic launchpad.  Clone everything except stdio.
171ffb1132eSMatt Morehouse   launchpad_t *lp;
172ffb1132eSMatt Morehouse   launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp);
173ffb1132eSMatt Morehouse   launchpad_load_from_file(lp, Argv[0]);
174ffb1132eSMatt Morehouse   launchpad_set_args(lp, Argc, Argv.get());
175ffb1132eSMatt Morehouse   launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO));
176ffb1132eSMatt Morehouse 
177ffb1132eSMatt Morehouse   // Determine stdout
178ffb1132eSMatt Morehouse   int FdOut = STDOUT_FILENO;
179*2f70693eSPetr Hosek 
180ffb1132eSMatt Morehouse   if (Cmd.hasOutputFile()) {
181ffb1132eSMatt Morehouse     auto Filename = Cmd.getOutputFile();
182*2f70693eSPetr Hosek     FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
183*2f70693eSPetr Hosek     if (FdOut == -1) {
184ffb1132eSMatt Morehouse       Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
185ffb1132eSMatt Morehouse              strerror(errno));
186ffb1132eSMatt Morehouse       return ZX_ERR_IO;
187ffb1132eSMatt Morehouse     }
188ffb1132eSMatt Morehouse   }
189*2f70693eSPetr Hosek   auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );
190ffb1132eSMatt Morehouse 
191ffb1132eSMatt Morehouse   // Determine stderr
192ffb1132eSMatt Morehouse   int FdErr = STDERR_FILENO;
193ffb1132eSMatt Morehouse   if (Cmd.isOutAndErrCombined())
194ffb1132eSMatt Morehouse     FdErr = FdOut;
195ffb1132eSMatt Morehouse 
196ffb1132eSMatt Morehouse   // Clone the file descriptors into the new process
197ffb1132eSMatt Morehouse   if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK ||
198ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK ||
199ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) {
200*2f70693eSPetr Hosek     Printf("libFuzzer: failed to clone FDIO: %s\n", _zx_status_get_string(rc));
201ffb1132eSMatt Morehouse     return rc;
202ffb1132eSMatt Morehouse   }
203ffb1132eSMatt Morehouse 
204ffb1132eSMatt Morehouse   // Start the process
205ffb1132eSMatt Morehouse   zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
206ffb1132eSMatt Morehouse   const char *ErrorMsg = nullptr;
207ffb1132eSMatt Morehouse   if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) {
208ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
209*2f70693eSPetr Hosek            _zx_status_get_string(rc));
210ffb1132eSMatt Morehouse     return rc;
211ffb1132eSMatt Morehouse   }
212*2f70693eSPetr Hosek   auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
213ffb1132eSMatt Morehouse 
214ffb1132eSMatt Morehouse   // Now join the process and return the exit status.
215*2f70693eSPetr Hosek   if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
216*2f70693eSPetr Hosek                                 ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
217ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
218*2f70693eSPetr Hosek            _zx_status_get_string(rc));
219ffb1132eSMatt Morehouse     return rc;
220ffb1132eSMatt Morehouse   }
221ffb1132eSMatt Morehouse 
222ffb1132eSMatt Morehouse   zx_info_process_t Info;
223*2f70693eSPetr Hosek   if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
224*2f70693eSPetr Hosek                                 sizeof(Info), nullptr, nullptr)) != ZX_OK) {
225ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
226ffb1132eSMatt Morehouse            zx_status_get_string(rc));
227ffb1132eSMatt Morehouse     return rc;
228ffb1132eSMatt Morehouse   }
229ffb1132eSMatt Morehouse 
230ffb1132eSMatt Morehouse   return Info.return_code;
231ffb1132eSMatt Morehouse }
232ffb1132eSMatt Morehouse 
233ffb1132eSMatt Morehouse const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
234ffb1132eSMatt Morehouse                          size_t PattLen) {
235ffb1132eSMatt Morehouse   return memmem(Data, DataLen, Patt, PattLen);
236ffb1132eSMatt Morehouse }
237ffb1132eSMatt Morehouse 
238ffb1132eSMatt Morehouse } // namespace fuzzer
239ffb1132eSMatt Morehouse 
240ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA
241