1*ffb1132eSMatt Morehouse //===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
2*ffb1132eSMatt Morehouse //
3*ffb1132eSMatt Morehouse //                     The LLVM Compiler Infrastructure
4*ffb1132eSMatt Morehouse //
5*ffb1132eSMatt Morehouse // This file is distributed under the University of Illinois Open Source
6*ffb1132eSMatt Morehouse // License. See LICENSE.TXT for details.
7*ffb1132eSMatt Morehouse //
8*ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===//
9*ffb1132eSMatt Morehouse // Misc utils implementation using Fuchsia/Zircon APIs.
10*ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===//
11*ffb1132eSMatt Morehouse #include "FuzzerDefs.h"
12*ffb1132eSMatt Morehouse 
13*ffb1132eSMatt Morehouse #if LIBFUZZER_FUCHSIA
14*ffb1132eSMatt Morehouse 
15*ffb1132eSMatt Morehouse #include "FuzzerInternal.h"
16*ffb1132eSMatt Morehouse #include "FuzzerUtil.h"
17*ffb1132eSMatt Morehouse #include <cerrno>
18*ffb1132eSMatt Morehouse #include <cinttypes>
19*ffb1132eSMatt Morehouse #include <cstdint>
20*ffb1132eSMatt Morehouse #include <fbl/unique_fd.h>
21*ffb1132eSMatt Morehouse #include <fcntl.h>
22*ffb1132eSMatt Morehouse #include <launchpad/launchpad.h>
23*ffb1132eSMatt Morehouse #include <string>
24*ffb1132eSMatt Morehouse #include <thread>
25*ffb1132eSMatt Morehouse #include <zircon/errors.h>
26*ffb1132eSMatt Morehouse #include <zircon/status.h>
27*ffb1132eSMatt Morehouse #include <zircon/syscalls.h>
28*ffb1132eSMatt Morehouse #include <zircon/syscalls/port.h>
29*ffb1132eSMatt Morehouse #include <zircon/types.h>
30*ffb1132eSMatt Morehouse #include <zx/object.h>
31*ffb1132eSMatt Morehouse #include <zx/port.h>
32*ffb1132eSMatt Morehouse #include <zx/process.h>
33*ffb1132eSMatt Morehouse #include <zx/time.h>
34*ffb1132eSMatt Morehouse 
35*ffb1132eSMatt Morehouse namespace fuzzer {
36*ffb1132eSMatt Morehouse 
37*ffb1132eSMatt Morehouse namespace {
38*ffb1132eSMatt Morehouse 
39*ffb1132eSMatt Morehouse // A magic value for the Zircon exception port, chosen to spell 'FUZZING'
40*ffb1132eSMatt Morehouse // when interpreted as a byte sequence on little-endian platforms.
41*ffb1132eSMatt Morehouse const uint64_t kFuzzingCrash = 0x474e495a5a5546;
42*ffb1132eSMatt Morehouse 
43*ffb1132eSMatt Morehouse void AlarmHandler(int Seconds) {
44*ffb1132eSMatt Morehouse   while (true) {
45*ffb1132eSMatt Morehouse     SleepSeconds(Seconds);
46*ffb1132eSMatt Morehouse     Fuzzer::StaticAlarmCallback();
47*ffb1132eSMatt Morehouse   }
48*ffb1132eSMatt Morehouse }
49*ffb1132eSMatt Morehouse 
50*ffb1132eSMatt Morehouse void InterruptHandler() {
51*ffb1132eSMatt Morehouse   // Ctrl-C sends ETX in Zircon.
52*ffb1132eSMatt Morehouse   while (getchar() != 0x03);
53*ffb1132eSMatt Morehouse   Fuzzer::StaticInterruptCallback();
54*ffb1132eSMatt Morehouse }
55*ffb1132eSMatt Morehouse 
56*ffb1132eSMatt Morehouse void CrashHandler(zx::port *Port) {
57*ffb1132eSMatt Morehouse   std::unique_ptr<zx::port> ExceptionPort(Port);
58*ffb1132eSMatt Morehouse   zx_port_packet_t Packet;
59*ffb1132eSMatt Morehouse   ExceptionPort->wait(ZX_TIME_INFINITE, &Packet, 0);
60*ffb1132eSMatt Morehouse   // Unbind as soon as possible so we don't receive exceptions from this thread.
61*ffb1132eSMatt Morehouse   if (zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID,
62*ffb1132eSMatt Morehouse                                   kFuzzingCrash, 0) != ZX_OK) {
63*ffb1132eSMatt Morehouse     // Shouldn't happen; if it does the safest option is to just exit.
64*ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to unbind exception port; aborting!\n");
65*ffb1132eSMatt Morehouse     exit(1);
66*ffb1132eSMatt Morehouse   }
67*ffb1132eSMatt Morehouse   if (Packet.key != kFuzzingCrash) {
68*ffb1132eSMatt Morehouse     Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n",
69*ffb1132eSMatt Morehouse            Packet.key);
70*ffb1132eSMatt Morehouse     exit(1);
71*ffb1132eSMatt Morehouse   }
72*ffb1132eSMatt Morehouse   // CrashCallback should not return from this call
73*ffb1132eSMatt Morehouse   Fuzzer::StaticCrashSignalCallback();
74*ffb1132eSMatt Morehouse }
75*ffb1132eSMatt Morehouse 
76*ffb1132eSMatt Morehouse } // namespace
77*ffb1132eSMatt Morehouse 
78*ffb1132eSMatt Morehouse // Platform specific functions.
79*ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) {
80*ffb1132eSMatt Morehouse   zx_status_t rc;
81*ffb1132eSMatt Morehouse 
82*ffb1132eSMatt Morehouse   // Set up alarm handler if needed.
83*ffb1132eSMatt Morehouse   if (Options.UnitTimeoutSec > 0) {
84*ffb1132eSMatt Morehouse     std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
85*ffb1132eSMatt Morehouse     T.detach();
86*ffb1132eSMatt Morehouse   }
87*ffb1132eSMatt Morehouse 
88*ffb1132eSMatt Morehouse   // Set up interrupt handler if needed.
89*ffb1132eSMatt Morehouse   if (Options.HandleInt || Options.HandleTerm) {
90*ffb1132eSMatt Morehouse     std::thread T(InterruptHandler);
91*ffb1132eSMatt Morehouse     T.detach();
92*ffb1132eSMatt Morehouse   }
93*ffb1132eSMatt Morehouse 
94*ffb1132eSMatt Morehouse   // Early exit if no crash handler needed.
95*ffb1132eSMatt Morehouse   if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
96*ffb1132eSMatt Morehouse       !Options.HandleFpe && !Options.HandleAbrt)
97*ffb1132eSMatt Morehouse     return;
98*ffb1132eSMatt Morehouse 
99*ffb1132eSMatt Morehouse   // Create an exception port
100*ffb1132eSMatt Morehouse   zx::port *ExceptionPort = new zx::port();
101*ffb1132eSMatt Morehouse   if ((rc = zx::port::create(0, ExceptionPort)) != ZX_OK) {
102*ffb1132eSMatt Morehouse     Printf("libFuzzer: zx_port_create failed: %s\n", zx_status_get_string(rc));
103*ffb1132eSMatt Morehouse     exit(1);
104*ffb1132eSMatt Morehouse   }
105*ffb1132eSMatt Morehouse 
106*ffb1132eSMatt Morehouse   // Bind the port to receive exceptions from our process
107*ffb1132eSMatt Morehouse   if ((rc = zx_task_bind_exception_port(zx_process_self(), ExceptionPort->get(),
108*ffb1132eSMatt Morehouse                                         kFuzzingCrash, 0)) != ZX_OK) {
109*ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to bind exception port: %s\n",
110*ffb1132eSMatt Morehouse            zx_status_get_string(rc));
111*ffb1132eSMatt Morehouse     exit(1);
112*ffb1132eSMatt Morehouse   }
113*ffb1132eSMatt Morehouse 
114*ffb1132eSMatt Morehouse   // Set up the crash handler.
115*ffb1132eSMatt Morehouse   std::thread T(CrashHandler, ExceptionPort);
116*ffb1132eSMatt Morehouse   T.detach();
117*ffb1132eSMatt Morehouse }
118*ffb1132eSMatt Morehouse 
119*ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) {
120*ffb1132eSMatt Morehouse   zx::nanosleep(zx::deadline_after(ZX_SEC(Seconds)));
121*ffb1132eSMatt Morehouse }
122*ffb1132eSMatt Morehouse 
123*ffb1132eSMatt Morehouse unsigned long GetPid() {
124*ffb1132eSMatt Morehouse   zx_status_t rc;
125*ffb1132eSMatt Morehouse   zx_info_handle_basic_t Info;
126*ffb1132eSMatt Morehouse   if ((rc = zx_object_get_info(zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
127*ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
128*ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
129*ffb1132eSMatt Morehouse            zx_status_get_string(rc));
130*ffb1132eSMatt Morehouse     exit(1);
131*ffb1132eSMatt Morehouse   }
132*ffb1132eSMatt Morehouse   return Info.koid;
133*ffb1132eSMatt Morehouse }
134*ffb1132eSMatt Morehouse 
135*ffb1132eSMatt Morehouse size_t GetPeakRSSMb() {
136*ffb1132eSMatt Morehouse   zx_status_t rc;
137*ffb1132eSMatt Morehouse   zx_info_task_stats_t Info;
138*ffb1132eSMatt Morehouse   if ((rc = zx_object_get_info(zx_process_self(), ZX_INFO_TASK_STATS, &Info,
139*ffb1132eSMatt Morehouse                                sizeof(Info), NULL, NULL)) != ZX_OK) {
140*ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get info about self: %s\n",
141*ffb1132eSMatt Morehouse            zx_status_get_string(rc));
142*ffb1132eSMatt Morehouse     exit(1);
143*ffb1132eSMatt Morehouse   }
144*ffb1132eSMatt Morehouse   return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
145*ffb1132eSMatt Morehouse }
146*ffb1132eSMatt Morehouse 
147*ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) {
148*ffb1132eSMatt Morehouse   zx_status_t rc;
149*ffb1132eSMatt Morehouse 
150*ffb1132eSMatt Morehouse   // Convert arguments to C array
151*ffb1132eSMatt Morehouse   auto Args = Cmd.getArguments();
152*ffb1132eSMatt Morehouse   size_t Argc = Args.size();
153*ffb1132eSMatt Morehouse   assert(Argc != 0);
154*ffb1132eSMatt Morehouse   std::unique_ptr<const char *[]> Argv(new const char *[Argc]);
155*ffb1132eSMatt Morehouse   for (size_t i = 0; i < Argc; ++i)
156*ffb1132eSMatt Morehouse     Argv[i] = Args[i].c_str();
157*ffb1132eSMatt Morehouse 
158*ffb1132eSMatt Morehouse   // Create the basic launchpad.  Clone everything except stdio.
159*ffb1132eSMatt Morehouse   launchpad_t *lp;
160*ffb1132eSMatt Morehouse   launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp);
161*ffb1132eSMatt Morehouse   launchpad_load_from_file(lp, Argv[0]);
162*ffb1132eSMatt Morehouse   launchpad_set_args(lp, Argc, Argv.get());
163*ffb1132eSMatt Morehouse   launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO));
164*ffb1132eSMatt Morehouse 
165*ffb1132eSMatt Morehouse   // Determine stdout
166*ffb1132eSMatt Morehouse   int FdOut = STDOUT_FILENO;
167*ffb1132eSMatt Morehouse   fbl::unique_fd OutputFile;
168*ffb1132eSMatt Morehouse   if (Cmd.hasOutputFile()) {
169*ffb1132eSMatt Morehouse     auto Filename = Cmd.getOutputFile();
170*ffb1132eSMatt Morehouse     OutputFile.reset(open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0));
171*ffb1132eSMatt Morehouse     if (!OutputFile) {
172*ffb1132eSMatt Morehouse       Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
173*ffb1132eSMatt Morehouse              strerror(errno));
174*ffb1132eSMatt Morehouse       return ZX_ERR_IO;
175*ffb1132eSMatt Morehouse     }
176*ffb1132eSMatt Morehouse     FdOut = OutputFile.get();
177*ffb1132eSMatt Morehouse   }
178*ffb1132eSMatt Morehouse 
179*ffb1132eSMatt Morehouse   // Determine stderr
180*ffb1132eSMatt Morehouse   int FdErr = STDERR_FILENO;
181*ffb1132eSMatt Morehouse   if (Cmd.isOutAndErrCombined())
182*ffb1132eSMatt Morehouse     FdErr = FdOut;
183*ffb1132eSMatt Morehouse 
184*ffb1132eSMatt Morehouse   // Clone the file descriptors into the new process
185*ffb1132eSMatt Morehouse   if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK ||
186*ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK ||
187*ffb1132eSMatt Morehouse       (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) {
188*ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to clone FDIO: %s\n", zx_status_get_string(rc));
189*ffb1132eSMatt Morehouse     return rc;
190*ffb1132eSMatt Morehouse   }
191*ffb1132eSMatt Morehouse 
192*ffb1132eSMatt Morehouse   // Start the process
193*ffb1132eSMatt Morehouse   zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
194*ffb1132eSMatt Morehouse   const char *ErrorMsg = nullptr;
195*ffb1132eSMatt Morehouse   if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) {
196*ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
197*ffb1132eSMatt Morehouse            zx_status_get_string(rc));
198*ffb1132eSMatt Morehouse     return rc;
199*ffb1132eSMatt Morehouse   }
200*ffb1132eSMatt Morehouse   zx::process Process(ProcessHandle);
201*ffb1132eSMatt Morehouse 
202*ffb1132eSMatt Morehouse   // Now join the process and return the exit status.
203*ffb1132eSMatt Morehouse   if ((rc = Process.wait_one(ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE,
204*ffb1132eSMatt Morehouse                              nullptr)) != ZX_OK) {
205*ffb1132eSMatt Morehouse     Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
206*ffb1132eSMatt Morehouse            zx_status_get_string(rc));
207*ffb1132eSMatt Morehouse     return rc;
208*ffb1132eSMatt Morehouse   }
209*ffb1132eSMatt Morehouse 
210*ffb1132eSMatt Morehouse   zx_info_process_t Info;
211*ffb1132eSMatt Morehouse   if ((rc = Process.get_info(ZX_INFO_PROCESS, &Info, sizeof(Info), nullptr,
212*ffb1132eSMatt Morehouse                              nullptr)) != ZX_OK) {
213*ffb1132eSMatt Morehouse     Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
214*ffb1132eSMatt Morehouse            zx_status_get_string(rc));
215*ffb1132eSMatt Morehouse     return rc;
216*ffb1132eSMatt Morehouse   }
217*ffb1132eSMatt Morehouse 
218*ffb1132eSMatt Morehouse   return Info.return_code;
219*ffb1132eSMatt Morehouse }
220*ffb1132eSMatt Morehouse 
221*ffb1132eSMatt Morehouse const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
222*ffb1132eSMatt Morehouse                          size_t PattLen) {
223*ffb1132eSMatt Morehouse   return memmem(Data, DataLen, Patt, PattLen);
224*ffb1132eSMatt Morehouse }
225*ffb1132eSMatt Morehouse 
226*ffb1132eSMatt Morehouse } // namespace fuzzer
227*ffb1132eSMatt Morehouse 
228*ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA
229