1ffb1132eSMatt Morehouse //===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===// 2ffb1132eSMatt Morehouse // 3ffb1132eSMatt Morehouse // The LLVM Compiler Infrastructure 4ffb1132eSMatt Morehouse // 5ffb1132eSMatt Morehouse // This file is distributed under the University of Illinois Open Source 6ffb1132eSMatt Morehouse // License. See LICENSE.TXT for details. 7ffb1132eSMatt Morehouse // 8ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===// 9ffb1132eSMatt Morehouse // Misc utils implementation using Fuchsia/Zircon APIs. 10ffb1132eSMatt Morehouse //===----------------------------------------------------------------------===// 11ffb1132eSMatt Morehouse #include "FuzzerDefs.h" 12ffb1132eSMatt Morehouse 13ffb1132eSMatt Morehouse #if LIBFUZZER_FUCHSIA 14ffb1132eSMatt Morehouse 15ffb1132eSMatt Morehouse #include "FuzzerInternal.h" 16ffb1132eSMatt Morehouse #include "FuzzerUtil.h" 17ffb1132eSMatt Morehouse #include <cerrno> 18ffb1132eSMatt Morehouse #include <cinttypes> 19ffb1132eSMatt Morehouse #include <cstdint> 20ffb1132eSMatt Morehouse #include <fcntl.h> 21*8908aa4eSPetr Hosek #include <fdio/spawn.h> 22ffb1132eSMatt Morehouse #include <string> 23dd097445SPetr Hosek #include <sys/select.h> 24ffb1132eSMatt Morehouse #include <thread> 252f70693eSPetr Hosek #include <unistd.h> 26ffb1132eSMatt Morehouse #include <zircon/errors.h> 272f70693eSPetr Hosek #include <zircon/process.h> 28ffb1132eSMatt Morehouse #include <zircon/status.h> 29ffb1132eSMatt Morehouse #include <zircon/syscalls.h> 30ffb1132eSMatt Morehouse #include <zircon/syscalls/port.h> 31ffb1132eSMatt Morehouse #include <zircon/types.h> 32ffb1132eSMatt Morehouse 33ffb1132eSMatt Morehouse namespace fuzzer { 34ffb1132eSMatt Morehouse 35ffb1132eSMatt Morehouse namespace { 36ffb1132eSMatt Morehouse 37ffb1132eSMatt Morehouse // A magic value for the Zircon exception port, chosen to spell 'FUZZING' 38ffb1132eSMatt Morehouse // when interpreted as a byte sequence on little-endian platforms. 39ffb1132eSMatt Morehouse const uint64_t kFuzzingCrash = 0x474e495a5a5546; 40ffb1132eSMatt Morehouse 41ffb1132eSMatt Morehouse void AlarmHandler(int Seconds) { 42ffb1132eSMatt Morehouse while (true) { 43ffb1132eSMatt Morehouse SleepSeconds(Seconds); 44ffb1132eSMatt Morehouse Fuzzer::StaticAlarmCallback(); 45ffb1132eSMatt Morehouse } 46ffb1132eSMatt Morehouse } 47ffb1132eSMatt Morehouse 48ffb1132eSMatt Morehouse void InterruptHandler() { 497a31c7adSPetr Hosek fd_set readfds; 50ffb1132eSMatt Morehouse // Ctrl-C sends ETX in Zircon. 517a31c7adSPetr Hosek do { 527a31c7adSPetr Hosek FD_ZERO(&readfds); 537a31c7adSPetr Hosek FD_SET(STDIN_FILENO, &readfds); 547a31c7adSPetr Hosek select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr); 557a31c7adSPetr Hosek } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03); 56ffb1132eSMatt Morehouse Fuzzer::StaticInterruptCallback(); 57ffb1132eSMatt Morehouse } 58ffb1132eSMatt Morehouse 592f70693eSPetr Hosek void CrashHandler(zx_handle_t *Port) { 602f70693eSPetr Hosek std::unique_ptr<zx_handle_t> ExceptionPort(Port); 61ffb1132eSMatt Morehouse zx_port_packet_t Packet; 62796bb7d4SPetr Hosek _zx_port_wait(*ExceptionPort, ZX_TIME_INFINITE, &Packet); 63ffb1132eSMatt Morehouse // Unbind as soon as possible so we don't receive exceptions from this thread. 642f70693eSPetr Hosek if (_zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID, 65ffb1132eSMatt Morehouse kFuzzingCrash, 0) != ZX_OK) { 66ffb1132eSMatt Morehouse // Shouldn't happen; if it does the safest option is to just exit. 67ffb1132eSMatt Morehouse Printf("libFuzzer: unable to unbind exception port; aborting!\n"); 68ffb1132eSMatt Morehouse exit(1); 69ffb1132eSMatt Morehouse } 70ffb1132eSMatt Morehouse if (Packet.key != kFuzzingCrash) { 71ffb1132eSMatt Morehouse Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n", 72ffb1132eSMatt Morehouse Packet.key); 73ffb1132eSMatt Morehouse exit(1); 74ffb1132eSMatt Morehouse } 75ffb1132eSMatt Morehouse // CrashCallback should not return from this call 76ffb1132eSMatt Morehouse Fuzzer::StaticCrashSignalCallback(); 77ffb1132eSMatt Morehouse } 78ffb1132eSMatt Morehouse 79ffb1132eSMatt Morehouse } // namespace 80ffb1132eSMatt Morehouse 81ffb1132eSMatt Morehouse // Platform specific functions. 82ffb1132eSMatt Morehouse void SetSignalHandler(const FuzzingOptions &Options) { 83ffb1132eSMatt Morehouse zx_status_t rc; 84ffb1132eSMatt Morehouse 85ffb1132eSMatt Morehouse // Set up alarm handler if needed. 86ffb1132eSMatt Morehouse if (Options.UnitTimeoutSec > 0) { 87ffb1132eSMatt Morehouse std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); 88ffb1132eSMatt Morehouse T.detach(); 89ffb1132eSMatt Morehouse } 90ffb1132eSMatt Morehouse 91ffb1132eSMatt Morehouse // Set up interrupt handler if needed. 92ffb1132eSMatt Morehouse if (Options.HandleInt || Options.HandleTerm) { 93ffb1132eSMatt Morehouse std::thread T(InterruptHandler); 94ffb1132eSMatt Morehouse T.detach(); 95ffb1132eSMatt Morehouse } 96ffb1132eSMatt Morehouse 97ffb1132eSMatt Morehouse // Early exit if no crash handler needed. 98ffb1132eSMatt Morehouse if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll && 99ffb1132eSMatt Morehouse !Options.HandleFpe && !Options.HandleAbrt) 100ffb1132eSMatt Morehouse return; 101ffb1132eSMatt Morehouse 102ffb1132eSMatt Morehouse // Create an exception port 1032f70693eSPetr Hosek zx_handle_t *ExceptionPort = new zx_handle_t; 1042f70693eSPetr Hosek if ((rc = _zx_port_create(0, ExceptionPort)) != ZX_OK) { 1052f70693eSPetr Hosek Printf("libFuzzer: zx_port_create failed: %s\n", _zx_status_get_string(rc)); 106ffb1132eSMatt Morehouse exit(1); 107ffb1132eSMatt Morehouse } 108ffb1132eSMatt Morehouse 109ffb1132eSMatt Morehouse // Bind the port to receive exceptions from our process 1102f70693eSPetr Hosek if ((rc = _zx_task_bind_exception_port(_zx_process_self(), *ExceptionPort, 111ffb1132eSMatt Morehouse kFuzzingCrash, 0)) != ZX_OK) { 112ffb1132eSMatt Morehouse Printf("libFuzzer: unable to bind exception port: %s\n", 113796bb7d4SPetr Hosek _zx_status_get_string(rc)); 114ffb1132eSMatt Morehouse exit(1); 115ffb1132eSMatt Morehouse } 116ffb1132eSMatt Morehouse 117ffb1132eSMatt Morehouse // Set up the crash handler. 118ffb1132eSMatt Morehouse std::thread T(CrashHandler, ExceptionPort); 119ffb1132eSMatt Morehouse T.detach(); 120ffb1132eSMatt Morehouse } 121ffb1132eSMatt Morehouse 122ffb1132eSMatt Morehouse void SleepSeconds(int Seconds) { 1232f70693eSPetr Hosek _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds))); 124ffb1132eSMatt Morehouse } 125ffb1132eSMatt Morehouse 126ffb1132eSMatt Morehouse unsigned long GetPid() { 127ffb1132eSMatt Morehouse zx_status_t rc; 128ffb1132eSMatt Morehouse zx_info_handle_basic_t Info; 129796bb7d4SPetr Hosek if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 130ffb1132eSMatt Morehouse sizeof(Info), NULL, NULL)) != ZX_OK) { 131ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get info about self: %s\n", 132796bb7d4SPetr Hosek _zx_status_get_string(rc)); 133ffb1132eSMatt Morehouse exit(1); 134ffb1132eSMatt Morehouse } 135ffb1132eSMatt Morehouse return Info.koid; 136ffb1132eSMatt Morehouse } 137ffb1132eSMatt Morehouse 138ffb1132eSMatt Morehouse size_t GetPeakRSSMb() { 139ffb1132eSMatt Morehouse zx_status_t rc; 140ffb1132eSMatt Morehouse zx_info_task_stats_t Info; 1412f70693eSPetr Hosek if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, 142ffb1132eSMatt Morehouse sizeof(Info), NULL, NULL)) != ZX_OK) { 143ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get info about self: %s\n", 1442f70693eSPetr Hosek _zx_status_get_string(rc)); 145ffb1132eSMatt Morehouse exit(1); 146ffb1132eSMatt Morehouse } 147ffb1132eSMatt Morehouse return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20; 148ffb1132eSMatt Morehouse } 149ffb1132eSMatt Morehouse 1502f70693eSPetr Hosek template <typename Fn> 1512f70693eSPetr Hosek class RunOnDestruction { 1522f70693eSPetr Hosek public: 1532f70693eSPetr Hosek explicit RunOnDestruction(Fn fn) : fn_(fn) {} 1542f70693eSPetr Hosek ~RunOnDestruction() { fn_(); } 1552f70693eSPetr Hosek 1562f70693eSPetr Hosek private: 1572f70693eSPetr Hosek Fn fn_; 1582f70693eSPetr Hosek }; 1592f70693eSPetr Hosek 1602f70693eSPetr Hosek template <typename Fn> 1612f70693eSPetr Hosek RunOnDestruction<Fn> at_scope_exit(Fn fn) { 1622f70693eSPetr Hosek return RunOnDestruction<Fn>(fn); 1632f70693eSPetr Hosek } 1642f70693eSPetr Hosek 165ffb1132eSMatt Morehouse int ExecuteCommand(const Command &Cmd) { 166ffb1132eSMatt Morehouse zx_status_t rc; 167ffb1132eSMatt Morehouse 168ffb1132eSMatt Morehouse // Convert arguments to C array 169ffb1132eSMatt Morehouse auto Args = Cmd.getArguments(); 170ffb1132eSMatt Morehouse size_t Argc = Args.size(); 171ffb1132eSMatt Morehouse assert(Argc != 0); 172*8908aa4eSPetr Hosek std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]); 173ffb1132eSMatt Morehouse for (size_t i = 0; i < Argc; ++i) 174ffb1132eSMatt Morehouse Argv[i] = Args[i].c_str(); 175*8908aa4eSPetr Hosek Argv[Argc] = nullptr; 176ffb1132eSMatt Morehouse 177ffb1132eSMatt Morehouse // Determine stdout 178ffb1132eSMatt Morehouse int FdOut = STDOUT_FILENO; 1792f70693eSPetr Hosek 180ffb1132eSMatt Morehouse if (Cmd.hasOutputFile()) { 181ffb1132eSMatt Morehouse auto Filename = Cmd.getOutputFile(); 1822f70693eSPetr Hosek FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); 1832f70693eSPetr Hosek if (FdOut == -1) { 184ffb1132eSMatt Morehouse Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(), 185ffb1132eSMatt Morehouse strerror(errno)); 186ffb1132eSMatt Morehouse return ZX_ERR_IO; 187ffb1132eSMatt Morehouse } 188ffb1132eSMatt Morehouse } 1892f70693eSPetr Hosek auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } ); 190ffb1132eSMatt Morehouse 191ffb1132eSMatt Morehouse // Determine stderr 192ffb1132eSMatt Morehouse int FdErr = STDERR_FILENO; 193ffb1132eSMatt Morehouse if (Cmd.isOutAndErrCombined()) 194ffb1132eSMatt Morehouse FdErr = FdOut; 195ffb1132eSMatt Morehouse 196ffb1132eSMatt Morehouse // Clone the file descriptors into the new process 197*8908aa4eSPetr Hosek fdio_spawn_action_t SpawnAction[] = { 198*8908aa4eSPetr Hosek { 199*8908aa4eSPetr Hosek .action = FDIO_SPAWN_ACTION_CLONE_FD, 200*8908aa4eSPetr Hosek .fd = 201*8908aa4eSPetr Hosek { 202*8908aa4eSPetr Hosek .local_fd = STDIN_FILENO, 203*8908aa4eSPetr Hosek .target_fd = STDIN_FILENO, 204*8908aa4eSPetr Hosek }, 205*8908aa4eSPetr Hosek }, 206*8908aa4eSPetr Hosek { 207*8908aa4eSPetr Hosek .action = FDIO_SPAWN_ACTION_CLONE_FD, 208*8908aa4eSPetr Hosek .fd = 209*8908aa4eSPetr Hosek { 210*8908aa4eSPetr Hosek .local_fd = FdOut, 211*8908aa4eSPetr Hosek .target_fd = STDOUT_FILENO, 212*8908aa4eSPetr Hosek }, 213*8908aa4eSPetr Hosek }, 214*8908aa4eSPetr Hosek { 215*8908aa4eSPetr Hosek .action = FDIO_SPAWN_ACTION_CLONE_FD, 216*8908aa4eSPetr Hosek .fd = 217*8908aa4eSPetr Hosek { 218*8908aa4eSPetr Hosek .local_fd = FdErr, 219*8908aa4eSPetr Hosek .target_fd = STDERR_FILENO, 220*8908aa4eSPetr Hosek }, 221*8908aa4eSPetr Hosek }, 222*8908aa4eSPetr Hosek }; 223ffb1132eSMatt Morehouse 224*8908aa4eSPetr Hosek // Start the process. 225*8908aa4eSPetr Hosek char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 226ffb1132eSMatt Morehouse zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; 227*8908aa4eSPetr Hosek rc = fdio_spawn_etc( 228*8908aa4eSPetr Hosek ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), 229*8908aa4eSPetr Hosek Argv[0], Argv.get(), nullptr, 3, SpawnAction, &ProcessHandle, ErrorMsg); 230*8908aa4eSPetr Hosek if (rc != ZX_OK) { 231ffb1132eSMatt Morehouse Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg, 2322f70693eSPetr Hosek _zx_status_get_string(rc)); 233ffb1132eSMatt Morehouse return rc; 234ffb1132eSMatt Morehouse } 2352f70693eSPetr Hosek auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); }); 236ffb1132eSMatt Morehouse 237ffb1132eSMatt Morehouse // Now join the process and return the exit status. 2382f70693eSPetr Hosek if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, 2392f70693eSPetr Hosek ZX_TIME_INFINITE, nullptr)) != ZX_OK) { 240ffb1132eSMatt Morehouse Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], 2412f70693eSPetr Hosek _zx_status_get_string(rc)); 242ffb1132eSMatt Morehouse return rc; 243ffb1132eSMatt Morehouse } 244ffb1132eSMatt Morehouse 245ffb1132eSMatt Morehouse zx_info_process_t Info; 2462f70693eSPetr Hosek if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, 2472f70693eSPetr Hosek sizeof(Info), nullptr, nullptr)) != ZX_OK) { 248ffb1132eSMatt Morehouse Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0], 249796bb7d4SPetr Hosek _zx_status_get_string(rc)); 250ffb1132eSMatt Morehouse return rc; 251ffb1132eSMatt Morehouse } 252ffb1132eSMatt Morehouse 253ffb1132eSMatt Morehouse return Info.return_code; 254ffb1132eSMatt Morehouse } 255ffb1132eSMatt Morehouse 256ffb1132eSMatt Morehouse const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 257ffb1132eSMatt Morehouse size_t PattLen) { 258ffb1132eSMatt Morehouse return memmem(Data, DataLen, Patt, PattLen); 259ffb1132eSMatt Morehouse } 260ffb1132eSMatt Morehouse 261ffb1132eSMatt Morehouse } // namespace fuzzer 262ffb1132eSMatt Morehouse 263ffb1132eSMatt Morehouse #endif // LIBFUZZER_FUCHSIA 264