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 //===----------------------------------------------------------------------===// 10ffb1132eSMatt Morehouse #include "FuzzerDefs.h" 11ffb1132eSMatt Morehouse 12ffb1132eSMatt Morehouse #if LIBFUZZER_FUCHSIA 13ffb1132eSMatt Morehouse 14ffb1132eSMatt Morehouse #include "FuzzerInternal.h" 15ffb1132eSMatt Morehouse #include "FuzzerUtil.h" 16ffb1132eSMatt Morehouse #include <cerrno> 17ffb1132eSMatt Morehouse #include <cinttypes> 18ffb1132eSMatt Morehouse #include <cstdint> 19ffb1132eSMatt Morehouse #include <fcntl.h> 20157a5c2fSPetr Hosek #include <lib/fdio/spawn.h> 21ffb1132eSMatt Morehouse #include <string> 22dd097445SPetr Hosek #include <sys/select.h> 23ffb1132eSMatt Morehouse #include <thread> 242f70693eSPetr Hosek #include <unistd.h> 25ffb1132eSMatt Morehouse #include <zircon/errors.h> 262f70693eSPetr Hosek #include <zircon/process.h> 274915d3a1SPetr Hosek #include <zircon/sanitizer.h> 28ffb1132eSMatt Morehouse #include <zircon/status.h> 29ffb1132eSMatt Morehouse #include <zircon/syscalls.h> 304915d3a1SPetr Hosek #include <zircon/syscalls/debug.h> 314915d3a1SPetr Hosek #include <zircon/syscalls/exception.h> 32ffb1132eSMatt Morehouse #include <zircon/syscalls/port.h> 33ffb1132eSMatt Morehouse #include <zircon/types.h> 34ffb1132eSMatt Morehouse 35ffb1132eSMatt Morehouse namespace fuzzer { 36ffb1132eSMatt Morehouse 374915d3a1SPetr Hosek // Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written 384915d3a1SPetr Hosek // around, the general approach is to spin up dedicated threads to watch for 394915d3a1SPetr Hosek // each requested condition (alarm, interrupt, crash). Of these, the crash 404915d3a1SPetr Hosek // handler is the most involved, as it requires resuming the crashed thread in 414915d3a1SPetr Hosek // order to invoke the sanitizers to get the needed state. 424915d3a1SPetr Hosek 434915d3a1SPetr Hosek // Forward declaration of assembly trampoline needed to resume crashed threads. 444915d3a1SPetr Hosek // This appears to have external linkage to C++, which is why it's not in the 454915d3a1SPetr Hosek // anonymous namespace. The assembly definition inside MakeTrampoline() 464915d3a1SPetr Hosek // actually defines the symbol with internal linkage only. 474915d3a1SPetr Hosek void CrashTrampolineAsm() __asm__("CrashTrampolineAsm"); 484915d3a1SPetr Hosek 49ffb1132eSMatt Morehouse namespace { 50ffb1132eSMatt Morehouse 51ffb1132eSMatt Morehouse // A magic value for the Zircon exception port, chosen to spell 'FUZZING' 52ffb1132eSMatt Morehouse // when interpreted as a byte sequence on little-endian platforms. 53ffb1132eSMatt Morehouse const uint64_t kFuzzingCrash = 0x474e495a5a5546; 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 71ffb1132eSMatt Morehouse void InterruptHandler() { 727a31c7adSPetr Hosek fd_set readfds; 73ffb1132eSMatt Morehouse // Ctrl-C sends ETX in Zircon. 747a31c7adSPetr Hosek do { 757a31c7adSPetr Hosek FD_ZERO(&readfds); 767a31c7adSPetr Hosek FD_SET(STDIN_FILENO, &readfds); 777a31c7adSPetr Hosek select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr); 787a31c7adSPetr Hosek } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03); 79ffb1132eSMatt Morehouse Fuzzer::StaticInterruptCallback(); 80ffb1132eSMatt Morehouse } 81ffb1132eSMatt Morehouse 824915d3a1SPetr Hosek // For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback 834915d3a1SPetr Hosek // without POSIX signal handlers. To achieve this, we use an assembly function 844915d3a1SPetr Hosek // to add the necessary CFI unwinding information and a C function to bridge 854915d3a1SPetr Hosek // from that back into C++. 864915d3a1SPetr Hosek 874915d3a1SPetr Hosek // FIXME: This works as a short-term solution, but this code really shouldn't be 884915d3a1SPetr Hosek // architecture dependent. A better long term solution is to implement remote 894915d3a1SPetr Hosek // unwinding and expose the necessary APIs through sanitizer_common and/or ASAN 904915d3a1SPetr Hosek // to allow the exception handling thread to gather the crash state directly. 914915d3a1SPetr Hosek // 924915d3a1SPetr Hosek // Alternatively, Fuchsia may in future actually implement basic signal 934915d3a1SPetr Hosek // handling for the machine trap signals. 944915d3a1SPetr Hosek #if defined(__x86_64__) 954915d3a1SPetr Hosek #define FOREACH_REGISTER(OP_REG, OP_NUM) \ 964915d3a1SPetr Hosek OP_REG(rax) \ 974915d3a1SPetr Hosek OP_REG(rbx) \ 984915d3a1SPetr Hosek OP_REG(rcx) \ 994915d3a1SPetr Hosek OP_REG(rdx) \ 1004915d3a1SPetr Hosek OP_REG(rsi) \ 1014915d3a1SPetr Hosek OP_REG(rdi) \ 1024915d3a1SPetr Hosek OP_REG(rbp) \ 1034915d3a1SPetr Hosek OP_REG(rsp) \ 1044915d3a1SPetr Hosek OP_REG(r8) \ 1054915d3a1SPetr Hosek OP_REG(r9) \ 1064915d3a1SPetr Hosek OP_REG(r10) \ 1074915d3a1SPetr Hosek OP_REG(r11) \ 1084915d3a1SPetr Hosek OP_REG(r12) \ 1094915d3a1SPetr Hosek OP_REG(r13) \ 1104915d3a1SPetr Hosek OP_REG(r14) \ 1114915d3a1SPetr Hosek OP_REG(r15) \ 1124915d3a1SPetr Hosek OP_REG(rip) 1134915d3a1SPetr Hosek 1144915d3a1SPetr Hosek #elif defined(__aarch64__) 1154915d3a1SPetr Hosek #define FOREACH_REGISTER(OP_REG, OP_NUM) \ 1164915d3a1SPetr Hosek OP_NUM(0) \ 1174915d3a1SPetr Hosek OP_NUM(1) \ 1184915d3a1SPetr Hosek OP_NUM(2) \ 1194915d3a1SPetr Hosek OP_NUM(3) \ 1204915d3a1SPetr Hosek OP_NUM(4) \ 1214915d3a1SPetr Hosek OP_NUM(5) \ 1224915d3a1SPetr Hosek OP_NUM(6) \ 1234915d3a1SPetr Hosek OP_NUM(7) \ 1244915d3a1SPetr Hosek OP_NUM(8) \ 1254915d3a1SPetr Hosek OP_NUM(9) \ 1264915d3a1SPetr Hosek OP_NUM(10) \ 1274915d3a1SPetr Hosek OP_NUM(11) \ 1284915d3a1SPetr Hosek OP_NUM(12) \ 1294915d3a1SPetr Hosek OP_NUM(13) \ 1304915d3a1SPetr Hosek OP_NUM(14) \ 1314915d3a1SPetr Hosek OP_NUM(15) \ 1324915d3a1SPetr Hosek OP_NUM(16) \ 1334915d3a1SPetr Hosek OP_NUM(17) \ 1344915d3a1SPetr Hosek OP_NUM(18) \ 1354915d3a1SPetr Hosek OP_NUM(19) \ 1364915d3a1SPetr Hosek OP_NUM(20) \ 1374915d3a1SPetr Hosek OP_NUM(21) \ 1384915d3a1SPetr Hosek OP_NUM(22) \ 1394915d3a1SPetr Hosek OP_NUM(23) \ 1404915d3a1SPetr Hosek OP_NUM(24) \ 1414915d3a1SPetr Hosek OP_NUM(25) \ 1424915d3a1SPetr Hosek OP_NUM(26) \ 1434915d3a1SPetr Hosek OP_NUM(27) \ 1444915d3a1SPetr Hosek OP_NUM(28) \ 1454915d3a1SPetr Hosek OP_NUM(29) \ 1464915d3a1SPetr Hosek OP_NUM(30) \ 1474915d3a1SPetr Hosek OP_REG(sp) 1484915d3a1SPetr Hosek 1494915d3a1SPetr Hosek #else 1504915d3a1SPetr Hosek #error "Unsupported architecture for fuzzing on Fuchsia" 1514915d3a1SPetr Hosek #endif 1524915d3a1SPetr Hosek 1534915d3a1SPetr Hosek // Produces a CFI directive for the named or numbered register. 1544915d3a1SPetr Hosek #define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n" 1554915d3a1SPetr Hosek #define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(r##num) 1564915d3a1SPetr Hosek 1574915d3a1SPetr Hosek // Produces an assembler input operand for the named or numbered register. 1584915d3a1SPetr Hosek #define ASM_OPERAND_REG(reg) \ 1594915d3a1SPetr Hosek [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg)), 1604915d3a1SPetr Hosek #define ASM_OPERAND_NUM(num) \ 1614915d3a1SPetr Hosek [r##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num])), 1624915d3a1SPetr Hosek 1634915d3a1SPetr Hosek // Trampoline to bridge from the assembly below to the static C++ crash 1644915d3a1SPetr Hosek // callback. 1654915d3a1SPetr Hosek __attribute__((noreturn)) 1664915d3a1SPetr Hosek static void StaticCrashHandler() { 167ffb1132eSMatt Morehouse Fuzzer::StaticCrashSignalCallback(); 1684915d3a1SPetr Hosek for (;;) { 1694915d3a1SPetr Hosek _Exit(1); 1704915d3a1SPetr Hosek } 1714915d3a1SPetr Hosek } 1724915d3a1SPetr Hosek 1734915d3a1SPetr Hosek // Creates the trampoline with the necessary CFI information to unwind through 1744915d3a1SPetr Hosek // to the crashing call stack. The attribute is necessary because the function 1754915d3a1SPetr Hosek // is never called; it's just a container around the assembly to allow it to 1764915d3a1SPetr Hosek // use operands for compile-time computed constants. 1774915d3a1SPetr Hosek __attribute__((used)) 1784915d3a1SPetr Hosek void MakeTrampoline() { 1794915d3a1SPetr Hosek __asm__(".cfi_endproc\n" 1804915d3a1SPetr Hosek ".pushsection .text.CrashTrampolineAsm\n" 1814915d3a1SPetr Hosek ".type CrashTrampolineAsm,STT_FUNC\n" 1824915d3a1SPetr Hosek "CrashTrampolineAsm:\n" 1834915d3a1SPetr Hosek ".cfi_startproc simple\n" 1844915d3a1SPetr Hosek ".cfi_signal_frame\n" 1854915d3a1SPetr Hosek #if defined(__x86_64__) 1864915d3a1SPetr Hosek ".cfi_return_column rip\n" 1874915d3a1SPetr Hosek ".cfi_def_cfa rsp, 0\n" 1884915d3a1SPetr Hosek FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) 1894915d3a1SPetr Hosek "call %c[StaticCrashHandler]\n" 1904915d3a1SPetr Hosek "ud2\n" 1914915d3a1SPetr Hosek #elif defined(__aarch64__) 1924915d3a1SPetr Hosek ".cfi_return_column 33\n" 1934915d3a1SPetr Hosek ".cfi_def_cfa sp, 0\n" 1944915d3a1SPetr Hosek ".cfi_offset 33, %c[pc]\n" 1954915d3a1SPetr Hosek FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) 1964915d3a1SPetr Hosek "bl %[StaticCrashHandler]\n" 1974915d3a1SPetr Hosek #else 1984915d3a1SPetr Hosek #error "Unsupported architecture for fuzzing on Fuchsia" 1994915d3a1SPetr Hosek #endif 2004915d3a1SPetr Hosek ".cfi_endproc\n" 2014915d3a1SPetr Hosek ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" 2024915d3a1SPetr Hosek ".popsection\n" 2034915d3a1SPetr Hosek ".cfi_startproc\n" 2044915d3a1SPetr Hosek : // No outputs 2054915d3a1SPetr Hosek : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) 2064915d3a1SPetr Hosek #if defined(__aarch64__) 2074915d3a1SPetr Hosek ASM_OPERAND_REG(pc) 2084915d3a1SPetr Hosek #endif 2094915d3a1SPetr Hosek [StaticCrashHandler] "i" (StaticCrashHandler)); 2104915d3a1SPetr Hosek } 2114915d3a1SPetr Hosek 2124915d3a1SPetr Hosek void CrashHandler(zx_handle_t *Event) { 2134915d3a1SPetr Hosek // This structure is used to ensure we close handles to objects we create in 2144915d3a1SPetr Hosek // this handler. 2154915d3a1SPetr Hosek struct ScopedHandle { 2164915d3a1SPetr Hosek ~ScopedHandle() { _zx_handle_close(Handle); } 2174915d3a1SPetr Hosek zx_handle_t Handle = ZX_HANDLE_INVALID; 2184915d3a1SPetr Hosek }; 2194915d3a1SPetr Hosek 2204915d3a1SPetr Hosek // Create and bind the exception port. We need to claim to be a "debugger" so 2214915d3a1SPetr Hosek // the kernel will allow us to modify and resume dying threads (see below). 2224915d3a1SPetr Hosek // Once the port is set, we can signal the main thread to continue and wait 2234915d3a1SPetr Hosek // for the exception to arrive. 2244915d3a1SPetr Hosek ScopedHandle Port; 2254915d3a1SPetr Hosek ExitOnErr(_zx_port_create(0, &Port.Handle), "_zx_port_create"); 2264915d3a1SPetr Hosek zx_handle_t Self = _zx_process_self(); 2274915d3a1SPetr Hosek 2284915d3a1SPetr Hosek ExitOnErr(_zx_task_bind_exception_port(Self, Port.Handle, kFuzzingCrash, 2294915d3a1SPetr Hosek ZX_EXCEPTION_PORT_DEBUGGER), 2304915d3a1SPetr Hosek "_zx_task_bind_exception_port"); 2314915d3a1SPetr Hosek 2324915d3a1SPetr Hosek ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0), 2334915d3a1SPetr Hosek "_zx_object_signal"); 2344915d3a1SPetr Hosek 2354915d3a1SPetr Hosek zx_port_packet_t Packet; 236118dc299SPetr Hosek ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE, &Packet), 2374915d3a1SPetr Hosek "_zx_port_wait"); 2384915d3a1SPetr Hosek 2394915d3a1SPetr Hosek // At this point, we want to get the state of the crashing thread, but 2404915d3a1SPetr Hosek // libFuzzer and the sanitizers assume this will happen from that same thread 2414915d3a1SPetr Hosek // via a POSIX signal handler. "Resurrecting" the thread in the middle of the 2424915d3a1SPetr Hosek // appropriate callback is as simple as forcibly setting the instruction 2434915d3a1SPetr Hosek // pointer/program counter, provided we NEVER EVER return from that function 2444915d3a1SPetr Hosek // (since otherwise our stack will not be valid). 2454915d3a1SPetr Hosek ScopedHandle Thread; 2464915d3a1SPetr Hosek ExitOnErr(_zx_object_get_child(Self, Packet.exception.tid, 2474915d3a1SPetr Hosek ZX_RIGHT_SAME_RIGHTS, &Thread.Handle), 2484915d3a1SPetr Hosek "_zx_object_get_child"); 2494915d3a1SPetr Hosek 2504915d3a1SPetr Hosek zx_thread_state_general_regs_t GeneralRegisters; 2514915d3a1SPetr Hosek ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, 2524915d3a1SPetr Hosek &GeneralRegisters, sizeof(GeneralRegisters)), 2534915d3a1SPetr Hosek "_zx_thread_read_state"); 2544915d3a1SPetr Hosek 2554915d3a1SPetr Hosek // To unwind properly, we need to push the crashing thread's register state 2564915d3a1SPetr Hosek // onto the stack and jump into a trampoline with CFI instructions on how 2574915d3a1SPetr Hosek // to restore it. 2584915d3a1SPetr Hosek #if defined(__x86_64__) 2594915d3a1SPetr Hosek uintptr_t StackPtr = 2604915d3a1SPetr Hosek (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) & 2614915d3a1SPetr Hosek -(uintptr_t)16; 2624915d3a1SPetr Hosek __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, 2634915d3a1SPetr Hosek sizeof(GeneralRegisters)); 2644915d3a1SPetr Hosek GeneralRegisters.rsp = StackPtr; 2654915d3a1SPetr Hosek GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); 2664915d3a1SPetr Hosek 2674915d3a1SPetr Hosek #elif defined(__aarch64__) 2684915d3a1SPetr Hosek uintptr_t StackPtr = 2694915d3a1SPetr Hosek (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16; 2704915d3a1SPetr Hosek __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, 2714915d3a1SPetr Hosek sizeof(GeneralRegisters)); 2724915d3a1SPetr Hosek GeneralRegisters.sp = StackPtr; 2734915d3a1SPetr Hosek GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); 2744915d3a1SPetr Hosek 2754915d3a1SPetr Hosek #else 2764915d3a1SPetr Hosek #error "Unsupported architecture for fuzzing on Fuchsia" 2774915d3a1SPetr Hosek #endif 2784915d3a1SPetr Hosek 2794915d3a1SPetr Hosek // Now force the crashing thread's state. 2804915d3a1SPetr Hosek ExitOnErr(_zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, 2814915d3a1SPetr Hosek &GeneralRegisters, sizeof(GeneralRegisters)), 2824915d3a1SPetr Hosek "_zx_thread_write_state"); 2834915d3a1SPetr Hosek 2844915d3a1SPetr Hosek ExitOnErr(_zx_task_resume_from_exception(Thread.Handle, Port.Handle, 0), 2854915d3a1SPetr Hosek "_zx_task_resume_from_exception"); 286ffb1132eSMatt Morehouse } 287ffb1132eSMatt Morehouse 288ffb1132eSMatt Morehouse } // namespace 289ffb1132eSMatt Morehouse 290*8da9479eSKostya Serebryany bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) { 291*8da9479eSKostya Serebryany return false; // UNIMPLEMENTED 292*8da9479eSKostya Serebryany } 293*8da9479eSKostya Serebryany 294ffb1132eSMatt Morehouse // Platform specific functions. 295ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) { 296ffb1132eSMatt Morehouse // Set up alarm handler if needed. 297ffb1132eSMatt Morehouse if (Options.UnitTimeoutSec > 0) { 298ffb1132eSMatt Morehouse std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); 299ffb1132eSMatt Morehouse T.detach(); 300ffb1132eSMatt Morehouse } 301ffb1132eSMatt Morehouse 302ffb1132eSMatt Morehouse // Set up interrupt handler if needed. 303ffb1132eSMatt Morehouse if (Options.HandleInt || Options.HandleTerm) { 304ffb1132eSMatt Morehouse std::thread T(InterruptHandler); 305ffb1132eSMatt Morehouse T.detach(); 306ffb1132eSMatt Morehouse } 307ffb1132eSMatt Morehouse 308ffb1132eSMatt Morehouse // Early exit if no crash handler needed. 309ffb1132eSMatt Morehouse if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll && 310ffb1132eSMatt Morehouse !Options.HandleFpe && !Options.HandleAbrt) 311ffb1132eSMatt Morehouse return; 312ffb1132eSMatt Morehouse 3134915d3a1SPetr Hosek // Set up the crash handler and wait until it is ready before proceeding. 3144915d3a1SPetr Hosek zx_handle_t Event; 3154915d3a1SPetr Hosek ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create"); 316ffb1132eSMatt Morehouse 3174915d3a1SPetr Hosek std::thread T(CrashHandler, &Event); 318118dc299SPetr Hosek zx_status_t Status = 319118dc299SPetr Hosek _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr); 3204915d3a1SPetr Hosek _zx_handle_close(Event); 3214915d3a1SPetr Hosek ExitOnErr(Status, "_zx_object_wait_one"); 322ffb1132eSMatt Morehouse 323ffb1132eSMatt Morehouse T.detach(); 324ffb1132eSMatt Morehouse } 325ffb1132eSMatt Morehouse 326ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) { 3272f70693eSPetr Hosek _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds))); 328ffb1132eSMatt Morehouse } 329ffb1132eSMatt Morehouse 330ffb1132eSMatt Morehouse unsigned long GetPid() { 331ffb1132eSMatt Morehouse zx_status_t rc; 332ffb1132eSMatt Morehouse zx_info_handle_basic_t Info; 333796bb7d4SPetr Hosek if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 334ffb1132eSMatt Morehouse sizeof(Info), NULL, NULL)) != ZX_OK) { 335ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get info about self: %s\n", 336796bb7d4SPetr Hosek _zx_status_get_string(rc)); 337ffb1132eSMatt Morehouse exit(1); 338ffb1132eSMatt Morehouse } 339ffb1132eSMatt Morehouse return Info.koid; 340ffb1132eSMatt Morehouse } 341ffb1132eSMatt Morehouse 342ffb1132eSMatt Morehouse size_t GetPeakRSSMb() { 343ffb1132eSMatt Morehouse zx_status_t rc; 344ffb1132eSMatt Morehouse zx_info_task_stats_t Info; 3452f70693eSPetr Hosek if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, 346ffb1132eSMatt Morehouse sizeof(Info), NULL, NULL)) != ZX_OK) { 347ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get info about self: %s\n", 3482f70693eSPetr Hosek _zx_status_get_string(rc)); 349ffb1132eSMatt Morehouse exit(1); 350ffb1132eSMatt Morehouse } 351ffb1132eSMatt Morehouse return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20; 352ffb1132eSMatt Morehouse } 353ffb1132eSMatt Morehouse 3542f70693eSPetr Hosek template <typename Fn> 3552f70693eSPetr Hosek class RunOnDestruction { 3562f70693eSPetr Hosek public: 3572f70693eSPetr Hosek explicit RunOnDestruction(Fn fn) : fn_(fn) {} 3582f70693eSPetr Hosek ~RunOnDestruction() { fn_(); } 3592f70693eSPetr Hosek 3602f70693eSPetr Hosek private: 3612f70693eSPetr Hosek Fn fn_; 3622f70693eSPetr Hosek }; 3632f70693eSPetr Hosek 3642f70693eSPetr Hosek template <typename Fn> 3652f70693eSPetr Hosek RunOnDestruction<Fn> at_scope_exit(Fn fn) { 3662f70693eSPetr Hosek return RunOnDestruction<Fn>(fn); 3672f70693eSPetr Hosek } 3682f70693eSPetr Hosek 369ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) { 370ffb1132eSMatt Morehouse zx_status_t rc; 371ffb1132eSMatt Morehouse 372ffb1132eSMatt Morehouse // Convert arguments to C array 373ffb1132eSMatt Morehouse auto Args = Cmd.getArguments(); 374ffb1132eSMatt Morehouse size_t Argc = Args.size(); 375ffb1132eSMatt Morehouse assert(Argc != 0); 3768908aa4eSPetr Hosek std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]); 377ffb1132eSMatt Morehouse for (size_t i = 0; i < Argc; ++i) 378ffb1132eSMatt Morehouse Argv[i] = Args[i].c_str(); 3798908aa4eSPetr Hosek Argv[Argc] = nullptr; 380ffb1132eSMatt Morehouse 381a70ece45SPetr Hosek // Determine output. On Fuchsia, the fuzzer is typically run as a component 382a70ece45SPetr Hosek // that lacks a mutable working directory. Fortunately, when this is the case 383a70ece45SPetr Hosek // a mutable output directory must be specified using "-artifact_prefix=...", 384a70ece45SPetr Hosek // so write the log file(s) there. 385ffb1132eSMatt Morehouse int FdOut = STDOUT_FILENO; 386ffb1132eSMatt Morehouse if (Cmd.hasOutputFile()) { 387a70ece45SPetr Hosek std::string Path; 388a70ece45SPetr Hosek if (Cmd.hasFlag("artifact_prefix")) 389a70ece45SPetr Hosek Path = Cmd.getFlagValue("artifact_prefix") + "/" + Cmd.getOutputFile(); 390a70ece45SPetr Hosek else 391a70ece45SPetr Hosek Path = Cmd.getOutputFile(); 392a70ece45SPetr Hosek FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); 3932f70693eSPetr Hosek if (FdOut == -1) { 394a70ece45SPetr Hosek Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(), 395ffb1132eSMatt Morehouse strerror(errno)); 396ffb1132eSMatt Morehouse return ZX_ERR_IO; 397ffb1132eSMatt Morehouse } 398ffb1132eSMatt Morehouse } 399a70ece45SPetr Hosek auto CloseFdOut = at_scope_exit([FdOut]() { 400a70ece45SPetr Hosek if (FdOut != STDOUT_FILENO) 401a70ece45SPetr Hosek close(FdOut); 402a70ece45SPetr Hosek }); 403ffb1132eSMatt Morehouse 404ffb1132eSMatt Morehouse // Determine stderr 405ffb1132eSMatt Morehouse int FdErr = STDERR_FILENO; 406ffb1132eSMatt Morehouse if (Cmd.isOutAndErrCombined()) 407ffb1132eSMatt Morehouse FdErr = FdOut; 408ffb1132eSMatt Morehouse 409ffb1132eSMatt Morehouse // Clone the file descriptors into the new process 4108908aa4eSPetr Hosek fdio_spawn_action_t SpawnAction[] = { 4118908aa4eSPetr Hosek { 4128908aa4eSPetr Hosek .action = FDIO_SPAWN_ACTION_CLONE_FD, 4138908aa4eSPetr Hosek .fd = 4148908aa4eSPetr Hosek { 4158908aa4eSPetr Hosek .local_fd = STDIN_FILENO, 4168908aa4eSPetr Hosek .target_fd = STDIN_FILENO, 4178908aa4eSPetr Hosek }, 4188908aa4eSPetr Hosek }, 4198908aa4eSPetr Hosek { 4208908aa4eSPetr Hosek .action = FDIO_SPAWN_ACTION_CLONE_FD, 4218908aa4eSPetr Hosek .fd = 4228908aa4eSPetr Hosek { 4238908aa4eSPetr Hosek .local_fd = FdOut, 4248908aa4eSPetr Hosek .target_fd = STDOUT_FILENO, 4258908aa4eSPetr Hosek }, 4268908aa4eSPetr Hosek }, 4278908aa4eSPetr Hosek { 4288908aa4eSPetr Hosek .action = FDIO_SPAWN_ACTION_CLONE_FD, 4298908aa4eSPetr Hosek .fd = 4308908aa4eSPetr Hosek { 4318908aa4eSPetr Hosek .local_fd = FdErr, 4328908aa4eSPetr Hosek .target_fd = STDERR_FILENO, 4338908aa4eSPetr Hosek }, 4348908aa4eSPetr Hosek }, 4358908aa4eSPetr Hosek }; 436ffb1132eSMatt Morehouse 4378908aa4eSPetr Hosek // Start the process. 4388908aa4eSPetr Hosek char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 439ffb1132eSMatt Morehouse zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; 4408908aa4eSPetr Hosek rc = fdio_spawn_etc( 4418908aa4eSPetr Hosek ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), 4428908aa4eSPetr Hosek Argv[0], Argv.get(), nullptr, 3, SpawnAction, &ProcessHandle, ErrorMsg); 4438908aa4eSPetr Hosek if (rc != ZX_OK) { 444ffb1132eSMatt Morehouse Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg, 4452f70693eSPetr Hosek _zx_status_get_string(rc)); 446ffb1132eSMatt Morehouse return rc; 447ffb1132eSMatt Morehouse } 4482f70693eSPetr Hosek auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); }); 449ffb1132eSMatt Morehouse 450ffb1132eSMatt Morehouse // Now join the process and return the exit status. 4512f70693eSPetr Hosek if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, 452118dc299SPetr Hosek ZX_TIME_INFINITE, nullptr)) != ZX_OK) { 453ffb1132eSMatt Morehouse Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], 4542f70693eSPetr Hosek _zx_status_get_string(rc)); 455ffb1132eSMatt Morehouse return rc; 456ffb1132eSMatt Morehouse } 457ffb1132eSMatt Morehouse 458ffb1132eSMatt Morehouse zx_info_process_t Info; 4592f70693eSPetr Hosek if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, 4602f70693eSPetr Hosek sizeof(Info), nullptr, nullptr)) != ZX_OK) { 461ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0], 462796bb7d4SPetr Hosek _zx_status_get_string(rc)); 463ffb1132eSMatt Morehouse return rc; 464ffb1132eSMatt Morehouse } 465ffb1132eSMatt Morehouse 466ffb1132eSMatt Morehouse return Info.return_code; 467ffb1132eSMatt Morehouse } 468ffb1132eSMatt Morehouse 469ffb1132eSMatt Morehouse const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 470ffb1132eSMatt Morehouse size_t PattLen) { 471ffb1132eSMatt Morehouse return memmem(Data, DataLen, Patt, PattLen); 472ffb1132eSMatt Morehouse } 473ffb1132eSMatt Morehouse 474ffb1132eSMatt Morehouse } // namespace fuzzer 475ffb1132eSMatt Morehouse 476ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA 477