1ffb1132eSMatt Morehouse //===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===// 2ffb1132eSMatt Morehouse // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ffb1132eSMatt Morehouse // 7ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===// 8ffb1132eSMatt Morehouse // Misc utils implementation using Fuchsia/Zircon APIs. 9ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===// 10226866e1SDokyung Song #include "FuzzerPlatform.h" 11ffb1132eSMatt Morehouse 12ffb1132eSMatt Morehouse #if LIBFUZZER_FUCHSIA 13ffb1132eSMatt Morehouse 14ffb1132eSMatt Morehouse #include "FuzzerInternal.h" 15ffb1132eSMatt Morehouse #include "FuzzerUtil.h" 169bd4dc92SPetr Hosek #include <cassert> 17ffb1132eSMatt Morehouse #include <cerrno> 18ffb1132eSMatt Morehouse #include <cinttypes> 19ffb1132eSMatt Morehouse #include <cstdint> 20ffb1132eSMatt Morehouse #include <fcntl.h> 21e5b603a4SMarco Vanotti #include <lib/fdio/fdio.h> 22157a5c2fSPetr Hosek #include <lib/fdio/spawn.h> 23ffb1132eSMatt Morehouse #include <string> 24dd097445SPetr Hosek #include <sys/select.h> 25ffb1132eSMatt Morehouse #include <thread> 262f70693eSPetr Hosek #include <unistd.h> 27ffb1132eSMatt Morehouse #include <zircon/errors.h> 282f70693eSPetr Hosek #include <zircon/process.h> 294915d3a1SPetr Hosek #include <zircon/sanitizer.h> 30ffb1132eSMatt Morehouse #include <zircon/status.h> 31ffb1132eSMatt Morehouse #include <zircon/syscalls.h> 324915d3a1SPetr Hosek #include <zircon/syscalls/debug.h> 334915d3a1SPetr Hosek #include <zircon/syscalls/exception.h> 34d9a59aebSPetr Hosek #include <zircon/syscalls/object.h> 35ffb1132eSMatt Morehouse #include <zircon/types.h> 36ffb1132eSMatt Morehouse 3744aaca3dSMarco Vanotti #include <vector> 3844aaca3dSMarco Vanotti 39ffb1132eSMatt Morehouse namespace fuzzer { 40ffb1132eSMatt Morehouse 414915d3a1SPetr Hosek // Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written 424915d3a1SPetr Hosek // around, the general approach is to spin up dedicated threads to watch for 434915d3a1SPetr Hosek // each requested condition (alarm, interrupt, crash). Of these, the crash 444915d3a1SPetr Hosek // handler is the most involved, as it requires resuming the crashed thread in 454915d3a1SPetr Hosek // order to invoke the sanitizers to get the needed state. 464915d3a1SPetr Hosek 474915d3a1SPetr Hosek // Forward declaration of assembly trampoline needed to resume crashed threads. 484915d3a1SPetr Hosek // This appears to have external linkage to C++, which is why it's not in the 494915d3a1SPetr Hosek // anonymous namespace. The assembly definition inside MakeTrampoline() 504915d3a1SPetr Hosek // actually defines the symbol with internal linkage only. 514915d3a1SPetr Hosek void CrashTrampolineAsm() __asm__("CrashTrampolineAsm"); 524915d3a1SPetr Hosek 53ffb1132eSMatt Morehouse namespace { 54ffb1132eSMatt Morehouse 554915d3a1SPetr Hosek // Helper function to handle Zircon syscall failures. 564915d3a1SPetr Hosek void ExitOnErr(zx_status_t Status, const char *Syscall) { 574915d3a1SPetr Hosek if (Status != ZX_OK) { 584915d3a1SPetr Hosek Printf("libFuzzer: %s failed: %s\n", Syscall, 594915d3a1SPetr Hosek _zx_status_get_string(Status)); 604915d3a1SPetr Hosek exit(1); 614915d3a1SPetr Hosek } 624915d3a1SPetr Hosek } 634915d3a1SPetr Hosek 64ffb1132eSMatt Morehouse void AlarmHandler(int Seconds) { 65ffb1132eSMatt Morehouse while (true) { 66ffb1132eSMatt Morehouse SleepSeconds(Seconds); 67ffb1132eSMatt Morehouse Fuzzer::StaticAlarmCallback(); 68ffb1132eSMatt Morehouse } 69ffb1132eSMatt Morehouse } 70ffb1132eSMatt Morehouse 7146c7fc22SMarco Vanotti // CFAOffset is used to reference the stack pointer before entering the 7246c7fc22SMarco Vanotti // trampoline (Stack Pointer + CFAOffset = prev Stack Pointer). Before jumping 7346c7fc22SMarco Vanotti // to the trampoline we copy all the registers onto the stack. We need to make 7446c7fc22SMarco Vanotti // sure that the new stack has enough space to store all the registers. 7546c7fc22SMarco Vanotti // 7646c7fc22SMarco Vanotti // The trampoline holds CFI information regarding the registers stored in the 7746c7fc22SMarco Vanotti // stack, which is then used by the unwinder to restore them. 7846c7fc22SMarco Vanotti #if defined(__x86_64__) 7946c7fc22SMarco Vanotti // In x86_64 the crashing function might also be using the red zone (128 bytes 8046c7fc22SMarco Vanotti // on top of their rsp). 8146c7fc22SMarco Vanotti constexpr size_t CFAOffset = 128 + sizeof(zx_thread_state_general_regs_t); 8246c7fc22SMarco Vanotti #elif defined(__aarch64__) 8346c7fc22SMarco Vanotti // In aarch64 we need to always have the stack pointer aligned to 16 bytes, so we 8446c7fc22SMarco Vanotti // make sure that we are keeping that same alignment. 8546c7fc22SMarco Vanotti constexpr size_t CFAOffset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(uintptr_t)16; 8646c7fc22SMarco Vanotti #endif 8746c7fc22SMarco Vanotti 884915d3a1SPetr Hosek // For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback 894915d3a1SPetr Hosek // without POSIX signal handlers. To achieve this, we use an assembly function 904915d3a1SPetr Hosek // to add the necessary CFI unwinding information and a C function to bridge 914915d3a1SPetr Hosek // from that back into C++. 924915d3a1SPetr Hosek 934915d3a1SPetr Hosek // FIXME: This works as a short-term solution, but this code really shouldn't be 944915d3a1SPetr Hosek // architecture dependent. A better long term solution is to implement remote 954915d3a1SPetr Hosek // unwinding and expose the necessary APIs through sanitizer_common and/or ASAN 964915d3a1SPetr Hosek // to allow the exception handling thread to gather the crash state directly. 974915d3a1SPetr Hosek // 984915d3a1SPetr Hosek // Alternatively, Fuchsia may in future actually implement basic signal 994915d3a1SPetr Hosek // handling for the machine trap signals. 1004915d3a1SPetr Hosek #if defined(__x86_64__) 1014915d3a1SPetr Hosek #define FOREACH_REGISTER(OP_REG, OP_NUM) \ 1024915d3a1SPetr Hosek OP_REG(rax) \ 1034915d3a1SPetr Hosek OP_REG(rbx) \ 1044915d3a1SPetr Hosek OP_REG(rcx) \ 1054915d3a1SPetr Hosek OP_REG(rdx) \ 1064915d3a1SPetr Hosek OP_REG(rsi) \ 1074915d3a1SPetr Hosek OP_REG(rdi) \ 1084915d3a1SPetr Hosek OP_REG(rbp) \ 1094915d3a1SPetr Hosek OP_REG(rsp) \ 1104915d3a1SPetr Hosek OP_REG(r8) \ 1114915d3a1SPetr Hosek OP_REG(r9) \ 1124915d3a1SPetr Hosek OP_REG(r10) \ 1134915d3a1SPetr Hosek OP_REG(r11) \ 1144915d3a1SPetr Hosek OP_REG(r12) \ 1154915d3a1SPetr Hosek OP_REG(r13) \ 1164915d3a1SPetr Hosek OP_REG(r14) \ 1174915d3a1SPetr Hosek OP_REG(r15) \ 1184915d3a1SPetr Hosek OP_REG(rip) 1194915d3a1SPetr Hosek 1204915d3a1SPetr Hosek #elif defined(__aarch64__) 1214915d3a1SPetr Hosek #define FOREACH_REGISTER(OP_REG, OP_NUM) \ 1224915d3a1SPetr Hosek OP_NUM(0) \ 1234915d3a1SPetr Hosek OP_NUM(1) \ 1244915d3a1SPetr Hosek OP_NUM(2) \ 1254915d3a1SPetr Hosek OP_NUM(3) \ 1264915d3a1SPetr Hosek OP_NUM(4) \ 1274915d3a1SPetr Hosek OP_NUM(5) \ 1284915d3a1SPetr Hosek OP_NUM(6) \ 1294915d3a1SPetr Hosek OP_NUM(7) \ 1304915d3a1SPetr Hosek OP_NUM(8) \ 1314915d3a1SPetr Hosek OP_NUM(9) \ 1324915d3a1SPetr Hosek OP_NUM(10) \ 1334915d3a1SPetr Hosek OP_NUM(11) \ 1344915d3a1SPetr Hosek OP_NUM(12) \ 1354915d3a1SPetr Hosek OP_NUM(13) \ 1364915d3a1SPetr Hosek OP_NUM(14) \ 1374915d3a1SPetr Hosek OP_NUM(15) \ 1384915d3a1SPetr Hosek OP_NUM(16) \ 1394915d3a1SPetr Hosek OP_NUM(17) \ 1404915d3a1SPetr Hosek OP_NUM(18) \ 1414915d3a1SPetr Hosek OP_NUM(19) \ 1424915d3a1SPetr Hosek OP_NUM(20) \ 1434915d3a1SPetr Hosek OP_NUM(21) \ 1444915d3a1SPetr Hosek OP_NUM(22) \ 1454915d3a1SPetr Hosek OP_NUM(23) \ 1464915d3a1SPetr Hosek OP_NUM(24) \ 1474915d3a1SPetr Hosek OP_NUM(25) \ 1484915d3a1SPetr Hosek OP_NUM(26) \ 1494915d3a1SPetr Hosek OP_NUM(27) \ 1504915d3a1SPetr Hosek OP_NUM(28) \ 1514915d3a1SPetr Hosek OP_NUM(29) \ 1524915d3a1SPetr Hosek OP_REG(sp) 1534915d3a1SPetr Hosek 1544915d3a1SPetr Hosek #else 1554915d3a1SPetr Hosek #error "Unsupported architecture for fuzzing on Fuchsia" 1564915d3a1SPetr Hosek #endif 1574915d3a1SPetr Hosek 1584915d3a1SPetr Hosek // Produces a CFI directive for the named or numbered register. 15946c7fc22SMarco Vanotti // The value used refers to an assembler immediate operand with the same name 16046c7fc22SMarco Vanotti // as the register (see ASM_OPERAND_REG). 1614915d3a1SPetr Hosek #define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n" 16246c7fc22SMarco Vanotti #define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(x##num) 1634915d3a1SPetr Hosek 16446c7fc22SMarco Vanotti // Produces an assembler immediate operand for the named or numbered register. 16546c7fc22SMarco Vanotti // This operand contains the offset of the register relative to the CFA. 1664915d3a1SPetr Hosek #define ASM_OPERAND_REG(reg) \ 16746c7fc22SMarco Vanotti [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg) - CFAOffset), 1684915d3a1SPetr Hosek #define ASM_OPERAND_NUM(num) \ 16946c7fc22SMarco Vanotti [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num]) - CFAOffset), 1704915d3a1SPetr Hosek 1714915d3a1SPetr Hosek // Trampoline to bridge from the assembly below to the static C++ crash 1724915d3a1SPetr Hosek // callback. 1734915d3a1SPetr Hosek __attribute__((noreturn)) 1744915d3a1SPetr Hosek static void StaticCrashHandler() { 175ffb1132eSMatt Morehouse Fuzzer::StaticCrashSignalCallback(); 1764915d3a1SPetr Hosek for (;;) { 1774915d3a1SPetr Hosek _Exit(1); 1784915d3a1SPetr Hosek } 1794915d3a1SPetr Hosek } 1804915d3a1SPetr Hosek 1814915d3a1SPetr Hosek // Creates the trampoline with the necessary CFI information to unwind through 18246c7fc22SMarco Vanotti // to the crashing call stack: 18346c7fc22SMarco Vanotti // * Defining the CFA so that it points to the stack pointer at the point 18446c7fc22SMarco Vanotti // of crash. 18546c7fc22SMarco Vanotti // * Storing all registers at the point of crash in the stack and refer to them 18646c7fc22SMarco Vanotti // via CFI information (relative to the CFA). 18746c7fc22SMarco Vanotti // * Setting the return column so the unwinder knows how to continue unwinding. 18846c7fc22SMarco Vanotti // * (x86_64) making sure rsp is aligned before calling StaticCrashHandler. 18946c7fc22SMarco Vanotti // * Calling StaticCrashHandler that will trigger the unwinder. 19046c7fc22SMarco Vanotti // 19146c7fc22SMarco Vanotti // The __attribute__((used)) is necessary because the function 1924915d3a1SPetr Hosek // is never called; it's just a container around the assembly to allow it to 1934915d3a1SPetr Hosek // use operands for compile-time computed constants. 1944915d3a1SPetr Hosek __attribute__((used)) 1954915d3a1SPetr Hosek void MakeTrampoline() { 1964915d3a1SPetr Hosek __asm__(".cfi_endproc\n" 1974915d3a1SPetr Hosek ".pushsection .text.CrashTrampolineAsm\n" 1984915d3a1SPetr Hosek ".type CrashTrampolineAsm,STT_FUNC\n" 1994915d3a1SPetr Hosek "CrashTrampolineAsm:\n" 2004915d3a1SPetr Hosek ".cfi_startproc simple\n" 2014915d3a1SPetr Hosek ".cfi_signal_frame\n" 2024915d3a1SPetr Hosek #if defined(__x86_64__) 2034915d3a1SPetr Hosek ".cfi_return_column rip\n" 20446c7fc22SMarco Vanotti ".cfi_def_cfa rsp, %c[CFAOffset]\n" 2054915d3a1SPetr Hosek FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) 20646c7fc22SMarco Vanotti "mov %%rsp, %%rbp\n" 20746c7fc22SMarco Vanotti ".cfi_def_cfa_register rbp\n" 20846c7fc22SMarco Vanotti "andq $-16, %%rsp\n" 2094915d3a1SPetr Hosek "call %c[StaticCrashHandler]\n" 2104915d3a1SPetr Hosek "ud2\n" 2114915d3a1SPetr Hosek #elif defined(__aarch64__) 2124915d3a1SPetr Hosek ".cfi_return_column 33\n" 21346c7fc22SMarco Vanotti ".cfi_def_cfa sp, %c[CFAOffset]\n" 2144915d3a1SPetr Hosek FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) 21546c7fc22SMarco Vanotti ".cfi_offset 33, %c[pc]\n" 21646c7fc22SMarco Vanotti ".cfi_offset 30, %c[lr]\n" 21746c7fc22SMarco Vanotti "bl %c[StaticCrashHandler]\n" 21846c7fc22SMarco Vanotti "brk 1\n" 2194915d3a1SPetr Hosek #else 2204915d3a1SPetr Hosek #error "Unsupported architecture for fuzzing on Fuchsia" 2214915d3a1SPetr Hosek #endif 2224915d3a1SPetr Hosek ".cfi_endproc\n" 2234915d3a1SPetr Hosek ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" 2244915d3a1SPetr Hosek ".popsection\n" 2254915d3a1SPetr Hosek ".cfi_startproc\n" 2264915d3a1SPetr Hosek : // No outputs 2274915d3a1SPetr Hosek : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) 2284915d3a1SPetr Hosek #if defined(__aarch64__) 2294915d3a1SPetr Hosek ASM_OPERAND_REG(pc) 23046c7fc22SMarco Vanotti ASM_OPERAND_REG(lr) 2314915d3a1SPetr Hosek #endif 23246c7fc22SMarco Vanotti [StaticCrashHandler] "i" (StaticCrashHandler), 23346c7fc22SMarco Vanotti [CFAOffset] "i" (CFAOffset)); 2344915d3a1SPetr Hosek } 2354915d3a1SPetr Hosek 2364915d3a1SPetr Hosek void CrashHandler(zx_handle_t *Event) { 2374915d3a1SPetr Hosek // This structure is used to ensure we close handles to objects we create in 2384915d3a1SPetr Hosek // this handler. 2394915d3a1SPetr Hosek struct ScopedHandle { 2404915d3a1SPetr Hosek ~ScopedHandle() { _zx_handle_close(Handle); } 2414915d3a1SPetr Hosek zx_handle_t Handle = ZX_HANDLE_INVALID; 2424915d3a1SPetr Hosek }; 2434915d3a1SPetr Hosek 244d9a59aebSPetr Hosek // Create the exception channel. We need to claim to be a "debugger" so the 245d9a59aebSPetr Hosek // kernel will allow us to modify and resume dying threads (see below). Once 246d9a59aebSPetr Hosek // the channel is set, we can signal the main thread to continue and wait 2474915d3a1SPetr Hosek // for the exception to arrive. 248d9a59aebSPetr Hosek ScopedHandle Channel; 2494915d3a1SPetr Hosek zx_handle_t Self = _zx_process_self(); 250d9a59aebSPetr Hosek ExitOnErr(_zx_task_create_exception_channel( 251d9a59aebSPetr Hosek Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle), 252d9a59aebSPetr Hosek "_zx_task_create_exception_channel"); 2534915d3a1SPetr Hosek 2544915d3a1SPetr Hosek ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0), 2554915d3a1SPetr Hosek "_zx_object_signal"); 2564915d3a1SPetr Hosek 2579bd4dc92SPetr Hosek // This thread lives as long as the process in order to keep handling 2589bd4dc92SPetr Hosek // crashes. In practice, the first crashed thread to reach the end of the 2599bd4dc92SPetr Hosek // StaticCrashHandler will end the process. 2609bd4dc92SPetr Hosek while (true) { 261d9a59aebSPetr Hosek ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE, 262d9a59aebSPetr Hosek ZX_TIME_INFINITE, nullptr), 263d9a59aebSPetr Hosek "_zx_object_wait_one"); 264d9a59aebSPetr Hosek 265d9a59aebSPetr Hosek zx_exception_info_t ExceptionInfo; 266d9a59aebSPetr Hosek ScopedHandle Exception; 267d9a59aebSPetr Hosek ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo, 268d9a59aebSPetr Hosek &Exception.Handle, sizeof(ExceptionInfo), 1, 269d9a59aebSPetr Hosek nullptr, nullptr), 270d9a59aebSPetr Hosek "_zx_channel_read"); 2714915d3a1SPetr Hosek 2729bd4dc92SPetr Hosek // Ignore informational synthetic exceptions. 273d9a59aebSPetr Hosek if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type || 274d9a59aebSPetr Hosek ZX_EXCP_THREAD_EXITING == ExceptionInfo.type || 275d9a59aebSPetr Hosek ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) { 2769bd4dc92SPetr Hosek continue; 2779bd4dc92SPetr Hosek } 2789bd4dc92SPetr Hosek 2794915d3a1SPetr Hosek // At this point, we want to get the state of the crashing thread, but 2809bd4dc92SPetr Hosek // libFuzzer and the sanitizers assume this will happen from that same 2819bd4dc92SPetr Hosek // thread via a POSIX signal handler. "Resurrecting" the thread in the 2829bd4dc92SPetr Hosek // middle of the appropriate callback is as simple as forcibly setting the 2839bd4dc92SPetr Hosek // instruction pointer/program counter, provided we NEVER EVER return from 2849bd4dc92SPetr Hosek // that function (since otherwise our stack will not be valid). 2854915d3a1SPetr Hosek ScopedHandle Thread; 286d9a59aebSPetr Hosek ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle), 287d9a59aebSPetr Hosek "_zx_exception_get_thread"); 2884915d3a1SPetr Hosek 2894915d3a1SPetr Hosek zx_thread_state_general_regs_t GeneralRegisters; 2904915d3a1SPetr Hosek ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, 2919bd4dc92SPetr Hosek &GeneralRegisters, 2929bd4dc92SPetr Hosek sizeof(GeneralRegisters)), 2934915d3a1SPetr Hosek "_zx_thread_read_state"); 2944915d3a1SPetr Hosek 2954915d3a1SPetr Hosek // To unwind properly, we need to push the crashing thread's register state 2964915d3a1SPetr Hosek // onto the stack and jump into a trampoline with CFI instructions on how 2974915d3a1SPetr Hosek // to restore it. 2984915d3a1SPetr Hosek #if defined(__x86_64__) 29946c7fc22SMarco Vanotti uintptr_t StackPtr = GeneralRegisters.rsp - CFAOffset; 3004915d3a1SPetr Hosek __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, 3014915d3a1SPetr Hosek sizeof(GeneralRegisters)); 3024915d3a1SPetr Hosek GeneralRegisters.rsp = StackPtr; 3034915d3a1SPetr Hosek GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); 3044915d3a1SPetr Hosek 3054915d3a1SPetr Hosek #elif defined(__aarch64__) 30646c7fc22SMarco Vanotti uintptr_t StackPtr = GeneralRegisters.sp - CFAOffset; 3074915d3a1SPetr Hosek __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, 3084915d3a1SPetr Hosek sizeof(GeneralRegisters)); 3094915d3a1SPetr Hosek GeneralRegisters.sp = StackPtr; 3104915d3a1SPetr Hosek GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); 3114915d3a1SPetr Hosek 3124915d3a1SPetr Hosek #else 3134915d3a1SPetr Hosek #error "Unsupported architecture for fuzzing on Fuchsia" 3144915d3a1SPetr Hosek #endif 3154915d3a1SPetr Hosek 3164915d3a1SPetr Hosek // Now force the crashing thread's state. 3179bd4dc92SPetr Hosek ExitOnErr( 3189bd4dc92SPetr Hosek _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, 3194915d3a1SPetr Hosek &GeneralRegisters, sizeof(GeneralRegisters)), 3204915d3a1SPetr Hosek "_zx_thread_write_state"); 3214915d3a1SPetr Hosek 322d9a59aebSPetr Hosek // Set the exception to HANDLED so it resumes the thread on close. 323d9a59aebSPetr Hosek uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED; 324d9a59aebSPetr Hosek ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE, 325d9a59aebSPetr Hosek &ExceptionState, sizeof(ExceptionState)), 326d9a59aebSPetr Hosek "zx_object_set_property"); 327ffb1132eSMatt Morehouse } 3289bd4dc92SPetr Hosek } 329ffb1132eSMatt Morehouse 330ffb1132eSMatt Morehouse } // namespace 331ffb1132eSMatt Morehouse 332ffb1132eSMatt Morehouse // Platform specific functions. 333ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) { 3344b23c24bSJake Ehrlich // Make sure information from libFuzzer and the sanitizers are easy to 3354b23c24bSJake Ehrlich // reassemble. `__sanitizer_log_write` has the added benefit of ensuring the 3364b23c24bSJake Ehrlich // DSO map is always available for the symbolizer. 3374b23c24bSJake Ehrlich // A uint64_t fits in 20 chars, so 64 is plenty. 3384b23c24bSJake Ehrlich char Buf[64]; 3394b23c24bSJake Ehrlich memset(Buf, 0, sizeof(Buf)); 3404b23c24bSJake Ehrlich snprintf(Buf, sizeof(Buf), "==%lu== INFO: libFuzzer starting.\n", GetPid()); 3414b23c24bSJake Ehrlich if (EF->__sanitizer_log_write) 3424b23c24bSJake Ehrlich __sanitizer_log_write(Buf, sizeof(Buf)); 3434b23c24bSJake Ehrlich Printf("%s", Buf); 3444b23c24bSJake Ehrlich 345ffb1132eSMatt Morehouse // Set up alarm handler if needed. 3469df7ee34SIlya Leoshkevich if (Options.HandleAlrm && Options.UnitTimeoutSec > 0) { 347ffb1132eSMatt Morehouse std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); 348ffb1132eSMatt Morehouse T.detach(); 349ffb1132eSMatt Morehouse } 350ffb1132eSMatt Morehouse 3516777919dSCameron Finucane // Options.HandleInt and Options.HandleTerm are not supported on Fuchsia 352ffb1132eSMatt Morehouse 353ffb1132eSMatt Morehouse // Early exit if no crash handler needed. 354ffb1132eSMatt Morehouse if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll && 355ffb1132eSMatt Morehouse !Options.HandleFpe && !Options.HandleAbrt) 356ffb1132eSMatt Morehouse return; 357ffb1132eSMatt Morehouse 3584915d3a1SPetr Hosek // Set up the crash handler and wait until it is ready before proceeding. 3594915d3a1SPetr Hosek zx_handle_t Event; 3604915d3a1SPetr Hosek ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create"); 361ffb1132eSMatt Morehouse 3624915d3a1SPetr Hosek std::thread T(CrashHandler, &Event); 363118dc299SPetr Hosek zx_status_t Status = 364118dc299SPetr Hosek _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr); 3654915d3a1SPetr Hosek _zx_handle_close(Event); 3664915d3a1SPetr Hosek ExitOnErr(Status, "_zx_object_wait_one"); 367ffb1132eSMatt Morehouse 368ffb1132eSMatt Morehouse T.detach(); 369ffb1132eSMatt Morehouse } 370ffb1132eSMatt Morehouse 371ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) { 3722f70693eSPetr Hosek _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds))); 373ffb1132eSMatt Morehouse } 374ffb1132eSMatt Morehouse 375ffb1132eSMatt Morehouse unsigned long GetPid() { 376ffb1132eSMatt Morehouse zx_status_t rc; 377ffb1132eSMatt Morehouse zx_info_handle_basic_t Info; 378796bb7d4SPetr Hosek if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 379ffb1132eSMatt Morehouse sizeof(Info), NULL, NULL)) != ZX_OK) { 380ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get info about self: %s\n", 381796bb7d4SPetr Hosek _zx_status_get_string(rc)); 382ffb1132eSMatt Morehouse exit(1); 383ffb1132eSMatt Morehouse } 384ffb1132eSMatt Morehouse return Info.koid; 385ffb1132eSMatt Morehouse } 386ffb1132eSMatt Morehouse 387ffb1132eSMatt Morehouse size_t GetPeakRSSMb() { 388ffb1132eSMatt Morehouse zx_status_t rc; 389ffb1132eSMatt Morehouse zx_info_task_stats_t Info; 3902f70693eSPetr Hosek if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, 391ffb1132eSMatt Morehouse sizeof(Info), NULL, NULL)) != ZX_OK) { 392ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get info about self: %s\n", 3932f70693eSPetr Hosek _zx_status_get_string(rc)); 394ffb1132eSMatt Morehouse exit(1); 395ffb1132eSMatt Morehouse } 396ffb1132eSMatt Morehouse return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20; 397ffb1132eSMatt Morehouse } 398ffb1132eSMatt Morehouse 3992f70693eSPetr Hosek template <typename Fn> 4002f70693eSPetr Hosek class RunOnDestruction { 4012f70693eSPetr Hosek public: 4022f70693eSPetr Hosek explicit RunOnDestruction(Fn fn) : fn_(fn) {} 4032f70693eSPetr Hosek ~RunOnDestruction() { fn_(); } 4042f70693eSPetr Hosek 4052f70693eSPetr Hosek private: 4062f70693eSPetr Hosek Fn fn_; 4072f70693eSPetr Hosek }; 4082f70693eSPetr Hosek 4092f70693eSPetr Hosek template <typename Fn> 4102f70693eSPetr Hosek RunOnDestruction<Fn> at_scope_exit(Fn fn) { 4112f70693eSPetr Hosek return RunOnDestruction<Fn>(fn); 4122f70693eSPetr Hosek } 4132f70693eSPetr Hosek 41444aaca3dSMarco Vanotti static fdio_spawn_action_t clone_fd_action(int localFd, int targetFd) { 41544aaca3dSMarco Vanotti return { 41644aaca3dSMarco Vanotti .action = FDIO_SPAWN_ACTION_CLONE_FD, 41744aaca3dSMarco Vanotti .fd = 41844aaca3dSMarco Vanotti { 41944aaca3dSMarco Vanotti .local_fd = localFd, 42044aaca3dSMarco Vanotti .target_fd = targetFd, 42144aaca3dSMarco Vanotti }, 42244aaca3dSMarco Vanotti }; 42344aaca3dSMarco Vanotti } 42444aaca3dSMarco Vanotti 425ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) { 426ffb1132eSMatt Morehouse zx_status_t rc; 427ffb1132eSMatt Morehouse 428ffb1132eSMatt Morehouse // Convert arguments to C array 429ffb1132eSMatt Morehouse auto Args = Cmd.getArguments(); 430ffb1132eSMatt Morehouse size_t Argc = Args.size(); 431ffb1132eSMatt Morehouse assert(Argc != 0); 4328908aa4eSPetr Hosek std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]); 433ffb1132eSMatt Morehouse for (size_t i = 0; i < Argc; ++i) 434ffb1132eSMatt Morehouse Argv[i] = Args[i].c_str(); 4358908aa4eSPetr Hosek Argv[Argc] = nullptr; 436ffb1132eSMatt Morehouse 437a70ece45SPetr Hosek // Determine output. On Fuchsia, the fuzzer is typically run as a component 438a70ece45SPetr Hosek // that lacks a mutable working directory. Fortunately, when this is the case 439a70ece45SPetr Hosek // a mutable output directory must be specified using "-artifact_prefix=...", 440a70ece45SPetr Hosek // so write the log file(s) there. 441cde860a1SJake Ehrlich // However, we don't want to apply this logic for absolute paths. 442ffb1132eSMatt Morehouse int FdOut = STDOUT_FILENO; 44344aaca3dSMarco Vanotti bool discardStdout = false; 44444aaca3dSMarco Vanotti bool discardStderr = false; 44544aaca3dSMarco Vanotti 446ffb1132eSMatt Morehouse if (Cmd.hasOutputFile()) { 447cde860a1SJake Ehrlich std::string Path = Cmd.getOutputFile(); 44844aaca3dSMarco Vanotti if (Path == getDevNull()) { 44944aaca3dSMarco Vanotti // On Fuchsia, there's no "/dev/null" like-file, so we 45044aaca3dSMarco Vanotti // just don't copy the FDs into the spawned process. 45144aaca3dSMarco Vanotti discardStdout = true; 45244aaca3dSMarco Vanotti } else { 453cde860a1SJake Ehrlich bool IsAbsolutePath = Path.length() > 1 && Path[0] == '/'; 454cde860a1SJake Ehrlich if (!IsAbsolutePath && Cmd.hasFlag("artifact_prefix")) 455cde860a1SJake Ehrlich Path = Cmd.getFlagValue("artifact_prefix") + "/" + Path; 456cde860a1SJake Ehrlich 457a70ece45SPetr Hosek FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); 4582f70693eSPetr Hosek if (FdOut == -1) { 459a70ece45SPetr Hosek Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(), 460ffb1132eSMatt Morehouse strerror(errno)); 461ffb1132eSMatt Morehouse return ZX_ERR_IO; 462ffb1132eSMatt Morehouse } 463ffb1132eSMatt Morehouse } 46444aaca3dSMarco Vanotti } 465a70ece45SPetr Hosek auto CloseFdOut = at_scope_exit([FdOut]() { 466a70ece45SPetr Hosek if (FdOut != STDOUT_FILENO) 467a70ece45SPetr Hosek close(FdOut); 468a70ece45SPetr Hosek }); 469ffb1132eSMatt Morehouse 470ffb1132eSMatt Morehouse // Determine stderr 471ffb1132eSMatt Morehouse int FdErr = STDERR_FILENO; 47244aaca3dSMarco Vanotti if (Cmd.isOutAndErrCombined()) { 473ffb1132eSMatt Morehouse FdErr = FdOut; 47444aaca3dSMarco Vanotti if (discardStdout) 47544aaca3dSMarco Vanotti discardStderr = true; 47644aaca3dSMarco Vanotti } 477ffb1132eSMatt Morehouse 478ffb1132eSMatt Morehouse // Clone the file descriptors into the new process 47944aaca3dSMarco Vanotti std::vector<fdio_spawn_action_t> SpawnActions; 48044aaca3dSMarco Vanotti SpawnActions.push_back(clone_fd_action(STDIN_FILENO, STDIN_FILENO)); 48144aaca3dSMarco Vanotti 48244aaca3dSMarco Vanotti if (!discardStdout) 48344aaca3dSMarco Vanotti SpawnActions.push_back(clone_fd_action(FdOut, STDOUT_FILENO)); 48444aaca3dSMarco Vanotti if (!discardStderr) 48544aaca3dSMarco Vanotti SpawnActions.push_back(clone_fd_action(FdErr, STDERR_FILENO)); 486ffb1132eSMatt Morehouse 4878908aa4eSPetr Hosek // Start the process. 4888908aa4eSPetr Hosek char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 489ffb1132eSMatt Morehouse zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; 49044aaca3dSMarco Vanotti rc = fdio_spawn_etc(ZX_HANDLE_INVALID, 49144aaca3dSMarco Vanotti FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), Argv[0], 49244aaca3dSMarco Vanotti Argv.get(), nullptr, SpawnActions.size(), 49344aaca3dSMarco Vanotti SpawnActions.data(), &ProcessHandle, ErrorMsg); 49444aaca3dSMarco Vanotti 4958908aa4eSPetr Hosek if (rc != ZX_OK) { 496ffb1132eSMatt Morehouse Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg, 4972f70693eSPetr Hosek _zx_status_get_string(rc)); 498ffb1132eSMatt Morehouse return rc; 499ffb1132eSMatt Morehouse } 5002f70693eSPetr Hosek auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); }); 501ffb1132eSMatt Morehouse 502ffb1132eSMatt Morehouse // Now join the process and return the exit status. 5032f70693eSPetr Hosek if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, 504118dc299SPetr Hosek ZX_TIME_INFINITE, nullptr)) != ZX_OK) { 505ffb1132eSMatt Morehouse Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], 5062f70693eSPetr Hosek _zx_status_get_string(rc)); 507ffb1132eSMatt Morehouse return rc; 508ffb1132eSMatt Morehouse } 509ffb1132eSMatt Morehouse 510ffb1132eSMatt Morehouse zx_info_process_t Info; 5112f70693eSPetr Hosek if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, 5122f70693eSPetr Hosek sizeof(Info), nullptr, nullptr)) != ZX_OK) { 513ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0], 514796bb7d4SPetr Hosek _zx_status_get_string(rc)); 515ffb1132eSMatt Morehouse return rc; 516ffb1132eSMatt Morehouse } 517ffb1132eSMatt Morehouse 5186708186cSAaron Green return static_cast<int>(Info.return_code); 519ffb1132eSMatt Morehouse } 520ffb1132eSMatt Morehouse 5214caeb62eSYuanfang Chen bool ExecuteCommand(const Command &BaseCmd, std::string *CmdOutput) { 5224caeb62eSYuanfang Chen auto LogFilePath = TempPath("SimPopenOut", ".txt"); 5234caeb62eSYuanfang Chen Command Cmd(BaseCmd); 5244caeb62eSYuanfang Chen Cmd.setOutputFile(LogFilePath); 5254caeb62eSYuanfang Chen int Ret = ExecuteCommand(Cmd); 5264caeb62eSYuanfang Chen *CmdOutput = FileToString(LogFilePath); 5274caeb62eSYuanfang Chen RemoveFile(LogFilePath); 5284caeb62eSYuanfang Chen return Ret == 0; 5294caeb62eSYuanfang Chen } 5304caeb62eSYuanfang Chen 531*c5d72517SMarco Vanotti const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 532*c5d72517SMarco Vanotti size_t PattLen) { 533*c5d72517SMarco Vanotti return memmem(Data, DataLen, Patt, PattLen); 534*c5d72517SMarco Vanotti } 535*c5d72517SMarco Vanotti 536e5b603a4SMarco Vanotti // In fuchsia, accessing /dev/null is not supported. There's nothing 537e5b603a4SMarco Vanotti // similar to a file that discards everything that is written to it. 538e5b603a4SMarco Vanotti // The way of doing something similar in fuchsia is by using 539e5b603a4SMarco Vanotti // fdio_null_create and binding that to a file descriptor. 540e5b603a4SMarco Vanotti void DiscardOutput(int Fd) { 541e5b603a4SMarco Vanotti fdio_t *fdio_null = fdio_null_create(); 542e5b603a4SMarco Vanotti if (fdio_null == nullptr) return; 543e5b603a4SMarco Vanotti int nullfd = fdio_bind_to_fd(fdio_null, -1, 0); 544e5b603a4SMarco Vanotti if (nullfd < 0) return; 545e5b603a4SMarco Vanotti dup2(nullfd, Fd); 546e5b603a4SMarco Vanotti } 547e5b603a4SMarco Vanotti 548ffb1132eSMatt Morehouse } // namespace fuzzer 549ffb1132eSMatt Morehouse 550ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA 551