FuzzerUtilFuchsia.cpp revision 360784
1//===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// Misc utils implementation using Fuchsia/Zircon APIs.
9//===----------------------------------------------------------------------===//
10#include "FuzzerDefs.h"
11
12#if LIBFUZZER_FUCHSIA
13
14#include "FuzzerInternal.h"
15#include "FuzzerUtil.h"
16#include <cassert>
17#include <cerrno>
18#include <cinttypes>
19#include <cstdint>
20#include <fcntl.h>
21#include <lib/fdio/fdio.h>
22#include <lib/fdio/spawn.h>
23#include <string>
24#include <sys/select.h>
25#include <thread>
26#include <unistd.h>
27#include <zircon/errors.h>
28#include <zircon/process.h>
29#include <zircon/sanitizer.h>
30#include <zircon/status.h>
31#include <zircon/syscalls.h>
32#include <zircon/syscalls/debug.h>
33#include <zircon/syscalls/exception.h>
34#include <zircon/syscalls/object.h>
35#include <zircon/types.h>
36
37namespace fuzzer {
38
39// Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written
40// around, the general approach is to spin up dedicated threads to watch for
41// each requested condition (alarm, interrupt, crash).  Of these, the crash
42// handler is the most involved, as it requires resuming the crashed thread in
43// order to invoke the sanitizers to get the needed state.
44
45// Forward declaration of assembly trampoline needed to resume crashed threads.
46// This appears to have external linkage to  C++, which is why it's not in the
47// anonymous namespace.  The assembly definition inside MakeTrampoline()
48// actually defines the symbol with internal linkage only.
49void CrashTrampolineAsm() __asm__("CrashTrampolineAsm");
50
51namespace {
52
53// Helper function to handle Zircon syscall failures.
54void ExitOnErr(zx_status_t Status, const char *Syscall) {
55  if (Status != ZX_OK) {
56    Printf("libFuzzer: %s failed: %s\n", Syscall,
57           _zx_status_get_string(Status));
58    exit(1);
59  }
60}
61
62void AlarmHandler(int Seconds) {
63  while (true) {
64    SleepSeconds(Seconds);
65    Fuzzer::StaticAlarmCallback();
66  }
67}
68
69void InterruptHandler() {
70  fd_set readfds;
71  // Ctrl-C sends ETX in Zircon.
72  do {
73    FD_ZERO(&readfds);
74    FD_SET(STDIN_FILENO, &readfds);
75    select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr);
76  } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03);
77  Fuzzer::StaticInterruptCallback();
78}
79
80// CFAOffset is used to reference the stack pointer before entering the
81// trampoline (Stack Pointer + CFAOffset = prev Stack Pointer). Before jumping
82// to the trampoline we copy all the registers onto the stack. We need to make
83// sure that the new stack has enough space to store all the registers.
84//
85// The trampoline holds CFI information regarding the registers stored in the
86// stack, which is then used by the unwinder to restore them.
87#if defined(__x86_64__)
88// In x86_64 the crashing function might also be using the red zone (128 bytes
89// on top of their rsp).
90constexpr size_t CFAOffset = 128 + sizeof(zx_thread_state_general_regs_t);
91#elif defined(__aarch64__)
92// In aarch64 we need to always have the stack pointer aligned to 16 bytes, so we
93// make sure that we are keeping that same alignment.
94constexpr size_t CFAOffset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(uintptr_t)16;
95#endif
96
97// For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback
98// without POSIX signal handlers.  To achieve this, we use an assembly function
99// to add the necessary CFI unwinding information and a C function to bridge
100// from that back into C++.
101
102// FIXME: This works as a short-term solution, but this code really shouldn't be
103// architecture dependent. A better long term solution is to implement remote
104// unwinding and expose the necessary APIs through sanitizer_common and/or ASAN
105// to allow the exception handling thread to gather the crash state directly.
106//
107// Alternatively, Fuchsia may in future actually implement basic signal
108// handling for the machine trap signals.
109#if defined(__x86_64__)
110#define FOREACH_REGISTER(OP_REG, OP_NUM) \
111  OP_REG(rax)                            \
112  OP_REG(rbx)                            \
113  OP_REG(rcx)                            \
114  OP_REG(rdx)                            \
115  OP_REG(rsi)                            \
116  OP_REG(rdi)                            \
117  OP_REG(rbp)                            \
118  OP_REG(rsp)                            \
119  OP_REG(r8)                             \
120  OP_REG(r9)                             \
121  OP_REG(r10)                            \
122  OP_REG(r11)                            \
123  OP_REG(r12)                            \
124  OP_REG(r13)                            \
125  OP_REG(r14)                            \
126  OP_REG(r15)                            \
127  OP_REG(rip)
128
129#elif defined(__aarch64__)
130#define FOREACH_REGISTER(OP_REG, OP_NUM) \
131  OP_NUM(0)                              \
132  OP_NUM(1)                              \
133  OP_NUM(2)                              \
134  OP_NUM(3)                              \
135  OP_NUM(4)                              \
136  OP_NUM(5)                              \
137  OP_NUM(6)                              \
138  OP_NUM(7)                              \
139  OP_NUM(8)                              \
140  OP_NUM(9)                              \
141  OP_NUM(10)                             \
142  OP_NUM(11)                             \
143  OP_NUM(12)                             \
144  OP_NUM(13)                             \
145  OP_NUM(14)                             \
146  OP_NUM(15)                             \
147  OP_NUM(16)                             \
148  OP_NUM(17)                             \
149  OP_NUM(18)                             \
150  OP_NUM(19)                             \
151  OP_NUM(20)                             \
152  OP_NUM(21)                             \
153  OP_NUM(22)                             \
154  OP_NUM(23)                             \
155  OP_NUM(24)                             \
156  OP_NUM(25)                             \
157  OP_NUM(26)                             \
158  OP_NUM(27)                             \
159  OP_NUM(28)                             \
160  OP_NUM(29)                             \
161  OP_REG(sp)
162
163#else
164#error "Unsupported architecture for fuzzing on Fuchsia"
165#endif
166
167// Produces a CFI directive for the named or numbered register.
168// The value used refers to an assembler immediate operand with the same name
169// as the register (see ASM_OPERAND_REG).
170#define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n"
171#define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(x##num)
172
173// Produces an assembler immediate operand for the named or numbered register.
174// This operand contains the offset of the register relative to the CFA.
175#define ASM_OPERAND_REG(reg) \
176  [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg) - CFAOffset),
177#define ASM_OPERAND_NUM(num)                                 \
178  [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num]) - CFAOffset),
179
180// Trampoline to bridge from the assembly below to the static C++ crash
181// callback.
182__attribute__((noreturn))
183static void StaticCrashHandler() {
184  Fuzzer::StaticCrashSignalCallback();
185  for (;;) {
186    _Exit(1);
187  }
188}
189
190// Creates the trampoline with the necessary CFI information to unwind through
191// to the crashing call stack:
192//  * Defining the CFA so that it points to the stack pointer at the point
193//    of crash.
194//  * Storing all registers at the point of crash in the stack and refer to them
195//    via CFI information (relative to the CFA).
196//  * Setting the return column so the unwinder knows how to continue unwinding.
197//  * (x86_64) making sure rsp is aligned before calling StaticCrashHandler.
198//  * Calling StaticCrashHandler that will trigger the unwinder.
199//
200// The __attribute__((used)) is necessary because the function
201// is never called; it's just a container around the assembly to allow it to
202// use operands for compile-time computed constants.
203__attribute__((used))
204void MakeTrampoline() {
205  __asm__(".cfi_endproc\n"
206    ".pushsection .text.CrashTrampolineAsm\n"
207    ".type CrashTrampolineAsm,STT_FUNC\n"
208"CrashTrampolineAsm:\n"
209    ".cfi_startproc simple\n"
210    ".cfi_signal_frame\n"
211#if defined(__x86_64__)
212    ".cfi_return_column rip\n"
213    ".cfi_def_cfa rsp, %c[CFAOffset]\n"
214    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM)
215    "mov %%rsp, %%rbp\n"
216    ".cfi_def_cfa_register rbp\n"
217    "andq $-16, %%rsp\n"
218    "call %c[StaticCrashHandler]\n"
219    "ud2\n"
220#elif defined(__aarch64__)
221    ".cfi_return_column 33\n"
222    ".cfi_def_cfa sp, %c[CFAOffset]\n"
223    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM)
224    ".cfi_offset 33, %c[pc]\n"
225    ".cfi_offset 30, %c[lr]\n"
226    "bl %c[StaticCrashHandler]\n"
227    "brk 1\n"
228#else
229#error "Unsupported architecture for fuzzing on Fuchsia"
230#endif
231    ".cfi_endproc\n"
232    ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n"
233    ".popsection\n"
234    ".cfi_startproc\n"
235    : // No outputs
236    : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM)
237#if defined(__aarch64__)
238      ASM_OPERAND_REG(pc)
239      ASM_OPERAND_REG(lr)
240#endif
241      [StaticCrashHandler] "i" (StaticCrashHandler),
242      [CFAOffset] "i" (CFAOffset));
243}
244
245void CrashHandler(zx_handle_t *Event) {
246  // This structure is used to ensure we close handles to objects we create in
247  // this handler.
248  struct ScopedHandle {
249    ~ScopedHandle() { _zx_handle_close(Handle); }
250    zx_handle_t Handle = ZX_HANDLE_INVALID;
251  };
252
253  // Create the exception channel.  We need to claim to be a "debugger" so the
254  // kernel will allow us to modify and resume dying threads (see below). Once
255  // the channel is set, we can signal the main thread to continue and wait
256  // for the exception to arrive.
257  ScopedHandle Channel;
258  zx_handle_t Self = _zx_process_self();
259  ExitOnErr(_zx_task_create_exception_channel(
260                Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle),
261            "_zx_task_create_exception_channel");
262
263  ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0),
264            "_zx_object_signal");
265
266  // This thread lives as long as the process in order to keep handling
267  // crashes.  In practice, the first crashed thread to reach the end of the
268  // StaticCrashHandler will end the process.
269  while (true) {
270    ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE,
271                                  ZX_TIME_INFINITE, nullptr),
272              "_zx_object_wait_one");
273
274    zx_exception_info_t ExceptionInfo;
275    ScopedHandle Exception;
276    ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo,
277                               &Exception.Handle, sizeof(ExceptionInfo), 1,
278                               nullptr, nullptr),
279              "_zx_channel_read");
280
281    // Ignore informational synthetic exceptions.
282    if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type ||
283        ZX_EXCP_THREAD_EXITING == ExceptionInfo.type ||
284        ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) {
285      continue;
286    }
287
288    // At this point, we want to get the state of the crashing thread, but
289    // libFuzzer and the sanitizers assume this will happen from that same
290    // thread via a POSIX signal handler. "Resurrecting" the thread in the
291    // middle of the appropriate callback is as simple as forcibly setting the
292    // instruction pointer/program counter, provided we NEVER EVER return from
293    // that function (since otherwise our stack will not be valid).
294    ScopedHandle Thread;
295    ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle),
296              "_zx_exception_get_thread");
297
298    zx_thread_state_general_regs_t GeneralRegisters;
299    ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
300                                    &GeneralRegisters,
301                                    sizeof(GeneralRegisters)),
302              "_zx_thread_read_state");
303
304    // To unwind properly, we need to push the crashing thread's register state
305    // onto the stack and jump into a trampoline with CFI instructions on how
306    // to restore it.
307#if defined(__x86_64__)
308    uintptr_t StackPtr = GeneralRegisters.rsp - CFAOffset;
309    __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
310                         sizeof(GeneralRegisters));
311    GeneralRegisters.rsp = StackPtr;
312    GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
313
314#elif defined(__aarch64__)
315    uintptr_t StackPtr = GeneralRegisters.sp - CFAOffset;
316    __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
317                         sizeof(GeneralRegisters));
318    GeneralRegisters.sp = StackPtr;
319    GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
320
321#else
322#error "Unsupported architecture for fuzzing on Fuchsia"
323#endif
324
325    // Now force the crashing thread's state.
326    ExitOnErr(
327        _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
328                               &GeneralRegisters, sizeof(GeneralRegisters)),
329        "_zx_thread_write_state");
330
331    // Set the exception to HANDLED so it resumes the thread on close.
332    uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED;
333    ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE,
334                                      &ExceptionState, sizeof(ExceptionState)),
335              "zx_object_set_property");
336  }
337}
338
339} // namespace
340
341// Platform specific functions.
342void SetSignalHandler(const FuzzingOptions &Options) {
343  // Make sure information from libFuzzer and the sanitizers are easy to
344  // reassemble. `__sanitizer_log_write` has the added benefit of ensuring the
345  // DSO map is always available for the symbolizer.
346  // A uint64_t fits in 20 chars, so 64 is plenty.
347  char Buf[64];
348  memset(Buf, 0, sizeof(Buf));
349  snprintf(Buf, sizeof(Buf), "==%lu== INFO: libFuzzer starting.\n", GetPid());
350  if (EF->__sanitizer_log_write)
351    __sanitizer_log_write(Buf, sizeof(Buf));
352  Printf("%s", Buf);
353
354  // Set up alarm handler if needed.
355  if (Options.UnitTimeoutSec > 0) {
356    std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
357    T.detach();
358  }
359
360  // Set up interrupt handler if needed.
361  if (Options.HandleInt || Options.HandleTerm) {
362    std::thread T(InterruptHandler);
363    T.detach();
364  }
365
366  // Early exit if no crash handler needed.
367  if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
368      !Options.HandleFpe && !Options.HandleAbrt)
369    return;
370
371  // Set up the crash handler and wait until it is ready before proceeding.
372  zx_handle_t Event;
373  ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create");
374
375  std::thread T(CrashHandler, &Event);
376  zx_status_t Status =
377      _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr);
378  _zx_handle_close(Event);
379  ExitOnErr(Status, "_zx_object_wait_one");
380
381  T.detach();
382}
383
384void SleepSeconds(int Seconds) {
385  _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
386}
387
388unsigned long GetPid() {
389  zx_status_t rc;
390  zx_info_handle_basic_t Info;
391  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
392                                sizeof(Info), NULL, NULL)) != ZX_OK) {
393    Printf("libFuzzer: unable to get info about self: %s\n",
394           _zx_status_get_string(rc));
395    exit(1);
396  }
397  return Info.koid;
398}
399
400size_t GetPeakRSSMb() {
401  zx_status_t rc;
402  zx_info_task_stats_t Info;
403  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
404                                sizeof(Info), NULL, NULL)) != ZX_OK) {
405    Printf("libFuzzer: unable to get info about self: %s\n",
406           _zx_status_get_string(rc));
407    exit(1);
408  }
409  return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
410}
411
412template <typename Fn>
413class RunOnDestruction {
414 public:
415  explicit RunOnDestruction(Fn fn) : fn_(fn) {}
416  ~RunOnDestruction() { fn_(); }
417
418 private:
419  Fn fn_;
420};
421
422template <typename Fn>
423RunOnDestruction<Fn> at_scope_exit(Fn fn) {
424  return RunOnDestruction<Fn>(fn);
425}
426
427int ExecuteCommand(const Command &Cmd) {
428  zx_status_t rc;
429
430  // Convert arguments to C array
431  auto Args = Cmd.getArguments();
432  size_t Argc = Args.size();
433  assert(Argc != 0);
434  std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]);
435  for (size_t i = 0; i < Argc; ++i)
436    Argv[i] = Args[i].c_str();
437  Argv[Argc] = nullptr;
438
439  // Determine output.  On Fuchsia, the fuzzer is typically run as a component
440  // that lacks a mutable working directory. Fortunately, when this is the case
441  // a mutable output directory must be specified using "-artifact_prefix=...",
442  // so write the log file(s) there.
443  // However, we don't want to apply this logic for absolute paths.
444  int FdOut = STDOUT_FILENO;
445  if (Cmd.hasOutputFile()) {
446    std::string Path = Cmd.getOutputFile();
447    bool IsAbsolutePath = Path.length() > 1 && Path[0] == '/';
448    if (!IsAbsolutePath && Cmd.hasFlag("artifact_prefix"))
449      Path = Cmd.getFlagValue("artifact_prefix") + "/" + Path;
450
451    FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
452    if (FdOut == -1) {
453      Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(),
454             strerror(errno));
455      return ZX_ERR_IO;
456    }
457  }
458  auto CloseFdOut = at_scope_exit([FdOut]() {
459    if (FdOut != STDOUT_FILENO)
460      close(FdOut);
461  });
462
463  // Determine stderr
464  int FdErr = STDERR_FILENO;
465  if (Cmd.isOutAndErrCombined())
466    FdErr = FdOut;
467
468  // Clone the file descriptors into the new process
469  fdio_spawn_action_t SpawnAction[] = {
470      {
471          .action = FDIO_SPAWN_ACTION_CLONE_FD,
472          .fd =
473              {
474                  .local_fd = STDIN_FILENO,
475                  .target_fd = STDIN_FILENO,
476              },
477      },
478      {
479          .action = FDIO_SPAWN_ACTION_CLONE_FD,
480          .fd =
481              {
482                  .local_fd = FdOut,
483                  .target_fd = STDOUT_FILENO,
484              },
485      },
486      {
487          .action = FDIO_SPAWN_ACTION_CLONE_FD,
488          .fd =
489              {
490                  .local_fd = FdErr,
491                  .target_fd = STDERR_FILENO,
492              },
493      },
494  };
495
496  // Start the process.
497  char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
498  zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
499  rc = fdio_spawn_etc(
500      ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO),
501      Argv[0], Argv.get(), nullptr, 3, SpawnAction, &ProcessHandle, ErrorMsg);
502  if (rc != ZX_OK) {
503    Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
504           _zx_status_get_string(rc));
505    return rc;
506  }
507  auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
508
509  // Now join the process and return the exit status.
510  if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
511                                ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
512    Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
513           _zx_status_get_string(rc));
514    return rc;
515  }
516
517  zx_info_process_t Info;
518  if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
519                                sizeof(Info), nullptr, nullptr)) != ZX_OK) {
520    Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
521           _zx_status_get_string(rc));
522    return rc;
523  }
524
525  return Info.return_code;
526}
527
528const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
529                         size_t PattLen) {
530  return memmem(Data, DataLen, Patt, PattLen);
531}
532
533// In fuchsia, accessing /dev/null is not supported. There's nothing
534// similar to a file that discards everything that is written to it.
535// The way of doing something similar in fuchsia is by using
536// fdio_null_create and binding that to a file descriptor.
537void DiscardOutput(int Fd) {
538  fdio_t *fdio_null = fdio_null_create();
539  if (fdio_null == nullptr) return;
540  int nullfd = fdio_bind_to_fd(fdio_null, -1, 0);
541  if (nullfd < 0) return;
542  dup2(nullfd, Fd);
543}
544
545} // namespace fuzzer
546
547#endif // LIBFUZZER_FUCHSIA
548