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