1326943Sdim//===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
2326943Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6326943Sdim//
7326943Sdim//===----------------------------------------------------------------------===//
8326943Sdim// Misc utils implementation using Fuchsia/Zircon APIs.
9326943Sdim//===----------------------------------------------------------------------===//
10326943Sdim#include "FuzzerDefs.h"
11326943Sdim
12326943Sdim#if LIBFUZZER_FUCHSIA
13326943Sdim
14326943Sdim#include "FuzzerInternal.h"
15326943Sdim#include "FuzzerUtil.h"
16353358Sdim#include <cassert>
17326943Sdim#include <cerrno>
18326943Sdim#include <cinttypes>
19326943Sdim#include <cstdint>
20326943Sdim#include <fcntl.h>
21360784Sdim#include <lib/fdio/fdio.h>
22336817Sdim#include <lib/fdio/spawn.h>
23326943Sdim#include <string>
24336817Sdim#include <sys/select.h>
25326943Sdim#include <thread>
26336817Sdim#include <unistd.h>
27326943Sdim#include <zircon/errors.h>
28336817Sdim#include <zircon/process.h>
29336817Sdim#include <zircon/sanitizer.h>
30326943Sdim#include <zircon/status.h>
31326943Sdim#include <zircon/syscalls.h>
32336817Sdim#include <zircon/syscalls/debug.h>
33336817Sdim#include <zircon/syscalls/exception.h>
34353358Sdim#include <zircon/syscalls/object.h>
35326943Sdim#include <zircon/types.h>
36326943Sdim
37326943Sdimnamespace fuzzer {
38326943Sdim
39336817Sdim// Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written
40336817Sdim// around, the general approach is to spin up dedicated threads to watch for
41336817Sdim// each requested condition (alarm, interrupt, crash).  Of these, the crash
42336817Sdim// handler is the most involved, as it requires resuming the crashed thread in
43336817Sdim// order to invoke the sanitizers to get the needed state.
44336817Sdim
45336817Sdim// Forward declaration of assembly trampoline needed to resume crashed threads.
46336817Sdim// This appears to have external linkage to  C++, which is why it's not in the
47336817Sdim// anonymous namespace.  The assembly definition inside MakeTrampoline()
48336817Sdim// actually defines the symbol with internal linkage only.
49336817Sdimvoid CrashTrampolineAsm() __asm__("CrashTrampolineAsm");
50336817Sdim
51326943Sdimnamespace {
52326943Sdim
53336817Sdim// Helper function to handle Zircon syscall failures.
54336817Sdimvoid ExitOnErr(zx_status_t Status, const char *Syscall) {
55336817Sdim  if (Status != ZX_OK) {
56336817Sdim    Printf("libFuzzer: %s failed: %s\n", Syscall,
57336817Sdim           _zx_status_get_string(Status));
58336817Sdim    exit(1);
59336817Sdim  }
60336817Sdim}
61336817Sdim
62326943Sdimvoid AlarmHandler(int Seconds) {
63326943Sdim  while (true) {
64326943Sdim    SleepSeconds(Seconds);
65326943Sdim    Fuzzer::StaticAlarmCallback();
66326943Sdim  }
67326943Sdim}
68326943Sdim
69326943Sdimvoid InterruptHandler() {
70336817Sdim  fd_set readfds;
71326943Sdim  // Ctrl-C sends ETX in Zircon.
72336817Sdim  do {
73336817Sdim    FD_ZERO(&readfds);
74336817Sdim    FD_SET(STDIN_FILENO, &readfds);
75336817Sdim    select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr);
76336817Sdim  } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03);
77326943Sdim  Fuzzer::StaticInterruptCallback();
78326943Sdim}
79326943Sdim
80360784Sdim// CFAOffset is used to reference the stack pointer before entering the
81360784Sdim// trampoline (Stack Pointer + CFAOffset = prev Stack Pointer). Before jumping
82360784Sdim// to the trampoline we copy all the registers onto the stack. We need to make
83360784Sdim// sure that the new stack has enough space to store all the registers.
84360784Sdim//
85360784Sdim// The trampoline holds CFI information regarding the registers stored in the
86360784Sdim// stack, which is then used by the unwinder to restore them.
87360784Sdim#if defined(__x86_64__)
88360784Sdim// In x86_64 the crashing function might also be using the red zone (128 bytes
89360784Sdim// on top of their rsp).
90360784Sdimconstexpr size_t CFAOffset = 128 + sizeof(zx_thread_state_general_regs_t);
91360784Sdim#elif defined(__aarch64__)
92360784Sdim// In aarch64 we need to always have the stack pointer aligned to 16 bytes, so we
93360784Sdim// make sure that we are keeping that same alignment.
94360784Sdimconstexpr size_t CFAOffset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(uintptr_t)16;
95360784Sdim#endif
96360784Sdim
97336817Sdim// For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback
98336817Sdim// without POSIX signal handlers.  To achieve this, we use an assembly function
99336817Sdim// to add the necessary CFI unwinding information and a C function to bridge
100336817Sdim// from that back into C++.
101336817Sdim
102336817Sdim// FIXME: This works as a short-term solution, but this code really shouldn't be
103336817Sdim// architecture dependent. A better long term solution is to implement remote
104336817Sdim// unwinding and expose the necessary APIs through sanitizer_common and/or ASAN
105336817Sdim// to allow the exception handling thread to gather the crash state directly.
106336817Sdim//
107336817Sdim// Alternatively, Fuchsia may in future actually implement basic signal
108336817Sdim// handling for the machine trap signals.
109336817Sdim#if defined(__x86_64__)
110336817Sdim#define FOREACH_REGISTER(OP_REG, OP_NUM) \
111336817Sdim  OP_REG(rax)                            \
112336817Sdim  OP_REG(rbx)                            \
113336817Sdim  OP_REG(rcx)                            \
114336817Sdim  OP_REG(rdx)                            \
115336817Sdim  OP_REG(rsi)                            \
116336817Sdim  OP_REG(rdi)                            \
117336817Sdim  OP_REG(rbp)                            \
118336817Sdim  OP_REG(rsp)                            \
119336817Sdim  OP_REG(r8)                             \
120336817Sdim  OP_REG(r9)                             \
121336817Sdim  OP_REG(r10)                            \
122336817Sdim  OP_REG(r11)                            \
123336817Sdim  OP_REG(r12)                            \
124336817Sdim  OP_REG(r13)                            \
125336817Sdim  OP_REG(r14)                            \
126336817Sdim  OP_REG(r15)                            \
127336817Sdim  OP_REG(rip)
128336817Sdim
129336817Sdim#elif defined(__aarch64__)
130336817Sdim#define FOREACH_REGISTER(OP_REG, OP_NUM) \
131336817Sdim  OP_NUM(0)                              \
132336817Sdim  OP_NUM(1)                              \
133336817Sdim  OP_NUM(2)                              \
134336817Sdim  OP_NUM(3)                              \
135336817Sdim  OP_NUM(4)                              \
136336817Sdim  OP_NUM(5)                              \
137336817Sdim  OP_NUM(6)                              \
138336817Sdim  OP_NUM(7)                              \
139336817Sdim  OP_NUM(8)                              \
140336817Sdim  OP_NUM(9)                              \
141336817Sdim  OP_NUM(10)                             \
142336817Sdim  OP_NUM(11)                             \
143336817Sdim  OP_NUM(12)                             \
144336817Sdim  OP_NUM(13)                             \
145336817Sdim  OP_NUM(14)                             \
146336817Sdim  OP_NUM(15)                             \
147336817Sdim  OP_NUM(16)                             \
148336817Sdim  OP_NUM(17)                             \
149336817Sdim  OP_NUM(18)                             \
150336817Sdim  OP_NUM(19)                             \
151336817Sdim  OP_NUM(20)                             \
152336817Sdim  OP_NUM(21)                             \
153336817Sdim  OP_NUM(22)                             \
154336817Sdim  OP_NUM(23)                             \
155336817Sdim  OP_NUM(24)                             \
156336817Sdim  OP_NUM(25)                             \
157336817Sdim  OP_NUM(26)                             \
158336817Sdim  OP_NUM(27)                             \
159336817Sdim  OP_NUM(28)                             \
160336817Sdim  OP_NUM(29)                             \
161336817Sdim  OP_REG(sp)
162336817Sdim
163336817Sdim#else
164336817Sdim#error "Unsupported architecture for fuzzing on Fuchsia"
165336817Sdim#endif
166336817Sdim
167336817Sdim// Produces a CFI directive for the named or numbered register.
168360784Sdim// The value used refers to an assembler immediate operand with the same name
169360784Sdim// as the register (see ASM_OPERAND_REG).
170336817Sdim#define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n"
171360784Sdim#define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(x##num)
172336817Sdim
173360784Sdim// Produces an assembler immediate operand for the named or numbered register.
174360784Sdim// This operand contains the offset of the register relative to the CFA.
175336817Sdim#define ASM_OPERAND_REG(reg) \
176360784Sdim  [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg) - CFAOffset),
177336817Sdim#define ASM_OPERAND_NUM(num)                                 \
178360784Sdim  [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num]) - CFAOffset),
179336817Sdim
180336817Sdim// Trampoline to bridge from the assembly below to the static C++ crash
181336817Sdim// callback.
182336817Sdim__attribute__((noreturn))
183336817Sdimstatic void StaticCrashHandler() {
184336817Sdim  Fuzzer::StaticCrashSignalCallback();
185336817Sdim  for (;;) {
186336817Sdim    _Exit(1);
187326943Sdim  }
188326943Sdim}
189326943Sdim
190336817Sdim// Creates the trampoline with the necessary CFI information to unwind through
191360784Sdim// to the crashing call stack:
192360784Sdim//  * Defining the CFA so that it points to the stack pointer at the point
193360784Sdim//    of crash.
194360784Sdim//  * Storing all registers at the point of crash in the stack and refer to them
195360784Sdim//    via CFI information (relative to the CFA).
196360784Sdim//  * Setting the return column so the unwinder knows how to continue unwinding.
197360784Sdim//  * (x86_64) making sure rsp is aligned before calling StaticCrashHandler.
198360784Sdim//  * Calling StaticCrashHandler that will trigger the unwinder.
199360784Sdim//
200360784Sdim// The __attribute__((used)) is necessary because the function
201336817Sdim// is never called; it's just a container around the assembly to allow it to
202336817Sdim// use operands for compile-time computed constants.
203336817Sdim__attribute__((used))
204336817Sdimvoid MakeTrampoline() {
205336817Sdim  __asm__(".cfi_endproc\n"
206336817Sdim    ".pushsection .text.CrashTrampolineAsm\n"
207336817Sdim    ".type CrashTrampolineAsm,STT_FUNC\n"
208336817Sdim"CrashTrampolineAsm:\n"
209336817Sdim    ".cfi_startproc simple\n"
210336817Sdim    ".cfi_signal_frame\n"
211336817Sdim#if defined(__x86_64__)
212336817Sdim    ".cfi_return_column rip\n"
213360784Sdim    ".cfi_def_cfa rsp, %c[CFAOffset]\n"
214336817Sdim    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM)
215360784Sdim    "mov %%rsp, %%rbp\n"
216360784Sdim    ".cfi_def_cfa_register rbp\n"
217360784Sdim    "andq $-16, %%rsp\n"
218336817Sdim    "call %c[StaticCrashHandler]\n"
219336817Sdim    "ud2\n"
220336817Sdim#elif defined(__aarch64__)
221336817Sdim    ".cfi_return_column 33\n"
222360784Sdim    ".cfi_def_cfa sp, %c[CFAOffset]\n"
223360784Sdim    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM)
224336817Sdim    ".cfi_offset 33, %c[pc]\n"
225360784Sdim    ".cfi_offset 30, %c[lr]\n"
226360784Sdim    "bl %c[StaticCrashHandler]\n"
227360784Sdim    "brk 1\n"
228336817Sdim#else
229336817Sdim#error "Unsupported architecture for fuzzing on Fuchsia"
230336817Sdim#endif
231336817Sdim    ".cfi_endproc\n"
232336817Sdim    ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n"
233336817Sdim    ".popsection\n"
234336817Sdim    ".cfi_startproc\n"
235336817Sdim    : // No outputs
236336817Sdim    : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM)
237336817Sdim#if defined(__aarch64__)
238336817Sdim      ASM_OPERAND_REG(pc)
239360784Sdim      ASM_OPERAND_REG(lr)
240336817Sdim#endif
241360784Sdim      [StaticCrashHandler] "i" (StaticCrashHandler),
242360784Sdim      [CFAOffset] "i" (CFAOffset));
243336817Sdim}
244336817Sdim
245336817Sdimvoid CrashHandler(zx_handle_t *Event) {
246336817Sdim  // This structure is used to ensure we close handles to objects we create in
247336817Sdim  // this handler.
248336817Sdim  struct ScopedHandle {
249336817Sdim    ~ScopedHandle() { _zx_handle_close(Handle); }
250336817Sdim    zx_handle_t Handle = ZX_HANDLE_INVALID;
251336817Sdim  };
252336817Sdim
253353358Sdim  // Create the exception channel.  We need to claim to be a "debugger" so the
254353358Sdim  // kernel will allow us to modify and resume dying threads (see below). Once
255353358Sdim  // the channel is set, we can signal the main thread to continue and wait
256336817Sdim  // for the exception to arrive.
257353358Sdim  ScopedHandle Channel;
258336817Sdim  zx_handle_t Self = _zx_process_self();
259353358Sdim  ExitOnErr(_zx_task_create_exception_channel(
260353358Sdim                Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle),
261353358Sdim            "_zx_task_create_exception_channel");
262336817Sdim
263336817Sdim  ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0),
264336817Sdim            "_zx_object_signal");
265336817Sdim
266353358Sdim  // This thread lives as long as the process in order to keep handling
267353358Sdim  // crashes.  In practice, the first crashed thread to reach the end of the
268353358Sdim  // StaticCrashHandler will end the process.
269353358Sdim  while (true) {
270353358Sdim    ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE,
271353358Sdim                                  ZX_TIME_INFINITE, nullptr),
272353358Sdim              "_zx_object_wait_one");
273336817Sdim
274353358Sdim    zx_exception_info_t ExceptionInfo;
275353358Sdim    ScopedHandle Exception;
276353358Sdim    ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo,
277353358Sdim                               &Exception.Handle, sizeof(ExceptionInfo), 1,
278353358Sdim                               nullptr, nullptr),
279353358Sdim              "_zx_channel_read");
280336817Sdim
281353358Sdim    // Ignore informational synthetic exceptions.
282353358Sdim    if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type ||
283353358Sdim        ZX_EXCP_THREAD_EXITING == ExceptionInfo.type ||
284353358Sdim        ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) {
285353358Sdim      continue;
286353358Sdim    }
287336817Sdim
288353358Sdim    // At this point, we want to get the state of the crashing thread, but
289353358Sdim    // libFuzzer and the sanitizers assume this will happen from that same
290353358Sdim    // thread via a POSIX signal handler. "Resurrecting" the thread in the
291353358Sdim    // middle of the appropriate callback is as simple as forcibly setting the
292353358Sdim    // instruction pointer/program counter, provided we NEVER EVER return from
293353358Sdim    // that function (since otherwise our stack will not be valid).
294353358Sdim    ScopedHandle Thread;
295353358Sdim    ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle),
296353358Sdim              "_zx_exception_get_thread");
297353358Sdim
298353358Sdim    zx_thread_state_general_regs_t GeneralRegisters;
299353358Sdim    ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
300353358Sdim                                    &GeneralRegisters,
301353358Sdim                                    sizeof(GeneralRegisters)),
302353358Sdim              "_zx_thread_read_state");
303353358Sdim
304353358Sdim    // To unwind properly, we need to push the crashing thread's register state
305353358Sdim    // onto the stack and jump into a trampoline with CFI instructions on how
306353358Sdim    // to restore it.
307336817Sdim#if defined(__x86_64__)
308360784Sdim    uintptr_t StackPtr = GeneralRegisters.rsp - CFAOffset;
309353358Sdim    __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
310353358Sdim                         sizeof(GeneralRegisters));
311353358Sdim    GeneralRegisters.rsp = StackPtr;
312353358Sdim    GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
313336817Sdim
314336817Sdim#elif defined(__aarch64__)
315360784Sdim    uintptr_t StackPtr = GeneralRegisters.sp - CFAOffset;
316353358Sdim    __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
317353358Sdim                         sizeof(GeneralRegisters));
318353358Sdim    GeneralRegisters.sp = StackPtr;
319353358Sdim    GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
320336817Sdim
321336817Sdim#else
322336817Sdim#error "Unsupported architecture for fuzzing on Fuchsia"
323336817Sdim#endif
324336817Sdim
325353358Sdim    // Now force the crashing thread's state.
326353358Sdim    ExitOnErr(
327353358Sdim        _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
328353358Sdim                               &GeneralRegisters, sizeof(GeneralRegisters)),
329353358Sdim        "_zx_thread_write_state");
330336817Sdim
331353358Sdim    // Set the exception to HANDLED so it resumes the thread on close.
332353358Sdim    uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED;
333353358Sdim    ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE,
334353358Sdim                                      &ExceptionState, sizeof(ExceptionState)),
335353358Sdim              "zx_object_set_property");
336353358Sdim  }
337336817Sdim}
338336817Sdim
339326943Sdim} // namespace
340326943Sdim
341326943Sdim// Platform specific functions.
342326943Sdimvoid SetSignalHandler(const FuzzingOptions &Options) {
343360784Sdim  // Make sure information from libFuzzer and the sanitizers are easy to
344360784Sdim  // reassemble. `__sanitizer_log_write` has the added benefit of ensuring the
345360784Sdim  // DSO map is always available for the symbolizer.
346360784Sdim  // A uint64_t fits in 20 chars, so 64 is plenty.
347360784Sdim  char Buf[64];
348360784Sdim  memset(Buf, 0, sizeof(Buf));
349360784Sdim  snprintf(Buf, sizeof(Buf), "==%lu== INFO: libFuzzer starting.\n", GetPid());
350360784Sdim  if (EF->__sanitizer_log_write)
351360784Sdim    __sanitizer_log_write(Buf, sizeof(Buf));
352360784Sdim  Printf("%s", Buf);
353360784Sdim
354326943Sdim  // Set up alarm handler if needed.
355326943Sdim  if (Options.UnitTimeoutSec > 0) {
356326943Sdim    std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
357326943Sdim    T.detach();
358326943Sdim  }
359326943Sdim
360326943Sdim  // Set up interrupt handler if needed.
361326943Sdim  if (Options.HandleInt || Options.HandleTerm) {
362326943Sdim    std::thread T(InterruptHandler);
363326943Sdim    T.detach();
364326943Sdim  }
365326943Sdim
366326943Sdim  // Early exit if no crash handler needed.
367326943Sdim  if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
368326943Sdim      !Options.HandleFpe && !Options.HandleAbrt)
369326943Sdim    return;
370326943Sdim
371336817Sdim  // Set up the crash handler and wait until it is ready before proceeding.
372336817Sdim  zx_handle_t Event;
373336817Sdim  ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create");
374326943Sdim
375336817Sdim  std::thread T(CrashHandler, &Event);
376344779Sdim  zx_status_t Status =
377344779Sdim      _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr);
378336817Sdim  _zx_handle_close(Event);
379336817Sdim  ExitOnErr(Status, "_zx_object_wait_one");
380326943Sdim
381326943Sdim  T.detach();
382326943Sdim}
383326943Sdim
384326943Sdimvoid SleepSeconds(int Seconds) {
385336817Sdim  _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
386326943Sdim}
387326943Sdim
388326943Sdimunsigned long GetPid() {
389326943Sdim  zx_status_t rc;
390326943Sdim  zx_info_handle_basic_t Info;
391336817Sdim  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
392336817Sdim                                sizeof(Info), NULL, NULL)) != ZX_OK) {
393326943Sdim    Printf("libFuzzer: unable to get info about self: %s\n",
394336817Sdim           _zx_status_get_string(rc));
395326943Sdim    exit(1);
396326943Sdim  }
397326943Sdim  return Info.koid;
398326943Sdim}
399326943Sdim
400326943Sdimsize_t GetPeakRSSMb() {
401326943Sdim  zx_status_t rc;
402326943Sdim  zx_info_task_stats_t Info;
403336817Sdim  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
404336817Sdim                                sizeof(Info), NULL, NULL)) != ZX_OK) {
405326943Sdim    Printf("libFuzzer: unable to get info about self: %s\n",
406336817Sdim           _zx_status_get_string(rc));
407326943Sdim    exit(1);
408326943Sdim  }
409326943Sdim  return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
410326943Sdim}
411326943Sdim
412336817Sdimtemplate <typename Fn>
413336817Sdimclass RunOnDestruction {
414336817Sdim public:
415336817Sdim  explicit RunOnDestruction(Fn fn) : fn_(fn) {}
416336817Sdim  ~RunOnDestruction() { fn_(); }
417336817Sdim
418336817Sdim private:
419336817Sdim  Fn fn_;
420336817Sdim};
421336817Sdim
422336817Sdimtemplate <typename Fn>
423336817SdimRunOnDestruction<Fn> at_scope_exit(Fn fn) {
424336817Sdim  return RunOnDestruction<Fn>(fn);
425336817Sdim}
426336817Sdim
427326943Sdimint ExecuteCommand(const Command &Cmd) {
428326943Sdim  zx_status_t rc;
429326943Sdim
430326943Sdim  // Convert arguments to C array
431326943Sdim  auto Args = Cmd.getArguments();
432326943Sdim  size_t Argc = Args.size();
433326943Sdim  assert(Argc != 0);
434336817Sdim  std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]);
435326943Sdim  for (size_t i = 0; i < Argc; ++i)
436326943Sdim    Argv[i] = Args[i].c_str();
437336817Sdim  Argv[Argc] = nullptr;
438326943Sdim
439344779Sdim  // Determine output.  On Fuchsia, the fuzzer is typically run as a component
440344779Sdim  // that lacks a mutable working directory. Fortunately, when this is the case
441344779Sdim  // a mutable output directory must be specified using "-artifact_prefix=...",
442344779Sdim  // so write the log file(s) there.
443360784Sdim  // However, we don't want to apply this logic for absolute paths.
444326943Sdim  int FdOut = STDOUT_FILENO;
445326943Sdim  if (Cmd.hasOutputFile()) {
446360784Sdim    std::string Path = Cmd.getOutputFile();
447360784Sdim    bool IsAbsolutePath = Path.length() > 1 && Path[0] == '/';
448360784Sdim    if (!IsAbsolutePath && Cmd.hasFlag("artifact_prefix"))
449360784Sdim      Path = Cmd.getFlagValue("artifact_prefix") + "/" + Path;
450360784Sdim
451344779Sdim    FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
452336817Sdim    if (FdOut == -1) {
453344779Sdim      Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(),
454326943Sdim             strerror(errno));
455326943Sdim      return ZX_ERR_IO;
456326943Sdim    }
457326943Sdim  }
458344779Sdim  auto CloseFdOut = at_scope_exit([FdOut]() {
459344779Sdim    if (FdOut != STDOUT_FILENO)
460344779Sdim      close(FdOut);
461344779Sdim  });
462326943Sdim
463326943Sdim  // Determine stderr
464326943Sdim  int FdErr = STDERR_FILENO;
465326943Sdim  if (Cmd.isOutAndErrCombined())
466326943Sdim    FdErr = FdOut;
467326943Sdim
468326943Sdim  // Clone the file descriptors into the new process
469336817Sdim  fdio_spawn_action_t SpawnAction[] = {
470336817Sdim      {
471336817Sdim          .action = FDIO_SPAWN_ACTION_CLONE_FD,
472336817Sdim          .fd =
473336817Sdim              {
474336817Sdim                  .local_fd = STDIN_FILENO,
475336817Sdim                  .target_fd = STDIN_FILENO,
476336817Sdim              },
477336817Sdim      },
478336817Sdim      {
479336817Sdim          .action = FDIO_SPAWN_ACTION_CLONE_FD,
480336817Sdim          .fd =
481336817Sdim              {
482336817Sdim                  .local_fd = FdOut,
483336817Sdim                  .target_fd = STDOUT_FILENO,
484336817Sdim              },
485336817Sdim      },
486336817Sdim      {
487336817Sdim          .action = FDIO_SPAWN_ACTION_CLONE_FD,
488336817Sdim          .fd =
489336817Sdim              {
490336817Sdim                  .local_fd = FdErr,
491336817Sdim                  .target_fd = STDERR_FILENO,
492336817Sdim              },
493336817Sdim      },
494336817Sdim  };
495326943Sdim
496336817Sdim  // Start the process.
497336817Sdim  char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
498326943Sdim  zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
499336817Sdim  rc = fdio_spawn_etc(
500336817Sdim      ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO),
501336817Sdim      Argv[0], Argv.get(), nullptr, 3, SpawnAction, &ProcessHandle, ErrorMsg);
502336817Sdim  if (rc != ZX_OK) {
503326943Sdim    Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
504336817Sdim           _zx_status_get_string(rc));
505326943Sdim    return rc;
506326943Sdim  }
507336817Sdim  auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
508326943Sdim
509326943Sdim  // Now join the process and return the exit status.
510336817Sdim  if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
511344779Sdim                                ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
512326943Sdim    Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
513336817Sdim           _zx_status_get_string(rc));
514326943Sdim    return rc;
515326943Sdim  }
516326943Sdim
517326943Sdim  zx_info_process_t Info;
518336817Sdim  if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
519336817Sdim                                sizeof(Info), nullptr, nullptr)) != ZX_OK) {
520326943Sdim    Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
521336817Sdim           _zx_status_get_string(rc));
522326943Sdim    return rc;
523326943Sdim  }
524326943Sdim
525326943Sdim  return Info.return_code;
526326943Sdim}
527326943Sdim
528326943Sdimconst void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
529326943Sdim                         size_t PattLen) {
530326943Sdim  return memmem(Data, DataLen, Patt, PattLen);
531326943Sdim}
532326943Sdim
533360784Sdim// In fuchsia, accessing /dev/null is not supported. There's nothing
534360784Sdim// similar to a file that discards everything that is written to it.
535360784Sdim// The way of doing something similar in fuchsia is by using
536360784Sdim// fdio_null_create and binding that to a file descriptor.
537360784Sdimvoid DiscardOutput(int Fd) {
538360784Sdim  fdio_t *fdio_null = fdio_null_create();
539360784Sdim  if (fdio_null == nullptr) return;
540360784Sdim  int nullfd = fdio_bind_to_fd(fdio_null, -1, 0);
541360784Sdim  if (nullfd < 0) return;
542360784Sdim  dup2(nullfd, Fd);
543360784Sdim}
544360784Sdim
545326943Sdim} // namespace fuzzer
546326943Sdim
547326943Sdim#endif // LIBFUZZER_FUCHSIA
548