1 //===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // Misc utils implementation using Fuchsia/Zircon APIs. 10 //===----------------------------------------------------------------------===// 11 #include "FuzzerDefs.h" 12 13 #if LIBFUZZER_FUCHSIA 14 15 #include "FuzzerInternal.h" 16 #include "FuzzerUtil.h" 17 #include <cerrno> 18 #include <cinttypes> 19 #include <cstdint> 20 #include <fcntl.h> 21 #include <launchpad/launchpad.h> 22 #include <string> 23 #include <thread> 24 #include <unistd.h> 25 #include <zircon/errors.h> 26 #include <zircon/process.h> 27 #include <zircon/status.h> 28 #include <zircon/syscalls.h> 29 #include <zircon/syscalls/port.h> 30 #include <zircon/types.h> 31 32 namespace fuzzer { 33 34 namespace { 35 36 // A magic value for the Zircon exception port, chosen to spell 'FUZZING' 37 // when interpreted as a byte sequence on little-endian platforms. 38 const uint64_t kFuzzingCrash = 0x474e495a5a5546; 39 40 void AlarmHandler(int Seconds) { 41 while (true) { 42 SleepSeconds(Seconds); 43 Fuzzer::StaticAlarmCallback(); 44 } 45 } 46 47 void InterruptHandler() { 48 // Ctrl-C sends ETX in Zircon. 49 while (getchar() != 0x03); 50 Fuzzer::StaticInterruptCallback(); 51 } 52 53 void CrashHandler(zx_handle_t *Port) { 54 std::unique_ptr<zx_handle_t> ExceptionPort(Port); 55 zx_port_packet_t Packet; 56 _zx_port_wait(*ExceptionPort, ZX_TIME_INFINITE, &Packet, 1); 57 // Unbind as soon as possible so we don't receive exceptions from this thread. 58 if (_zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID, 59 kFuzzingCrash, 0) != ZX_OK) { 60 // Shouldn't happen; if it does the safest option is to just exit. 61 Printf("libFuzzer: unable to unbind exception port; aborting!\n"); 62 exit(1); 63 } 64 if (Packet.key != kFuzzingCrash) { 65 Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n", 66 Packet.key); 67 exit(1); 68 } 69 // CrashCallback should not return from this call 70 Fuzzer::StaticCrashSignalCallback(); 71 } 72 73 } // namespace 74 75 // Platform specific functions. 76 void SetSignalHandler(const FuzzingOptions &Options) { 77 zx_status_t rc; 78 79 // Set up alarm handler if needed. 80 if (Options.UnitTimeoutSec > 0) { 81 std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); 82 T.detach(); 83 } 84 85 // Set up interrupt handler if needed. 86 if (Options.HandleInt || Options.HandleTerm) { 87 std::thread T(InterruptHandler); 88 T.detach(); 89 } 90 91 // Early exit if no crash handler needed. 92 if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll && 93 !Options.HandleFpe && !Options.HandleAbrt) 94 return; 95 96 // Create an exception port 97 zx_handle_t *ExceptionPort = new zx_handle_t; 98 if ((rc = _zx_port_create(0, ExceptionPort)) != ZX_OK) { 99 Printf("libFuzzer: zx_port_create failed: %s\n", _zx_status_get_string(rc)); 100 exit(1); 101 } 102 103 // Bind the port to receive exceptions from our process 104 if ((rc = _zx_task_bind_exception_port(_zx_process_self(), *ExceptionPort, 105 kFuzzingCrash, 0)) != ZX_OK) { 106 Printf("libFuzzer: unable to bind exception port: %s\n", 107 zx_status_get_string(rc)); 108 exit(1); 109 } 110 111 // Set up the crash handler. 112 std::thread T(CrashHandler, ExceptionPort); 113 T.detach(); 114 } 115 116 void SleepSeconds(int Seconds) { 117 _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds))); 118 } 119 120 unsigned long GetPid() { 121 zx_status_t rc; 122 zx_info_handle_basic_t Info; 123 if ((rc = zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 124 sizeof(Info), NULL, NULL)) != ZX_OK) { 125 Printf("libFuzzer: unable to get info about self: %s\n", 126 zx_status_get_string(rc)); 127 exit(1); 128 } 129 return Info.koid; 130 } 131 132 size_t GetPeakRSSMb() { 133 zx_status_t rc; 134 zx_info_task_stats_t Info; 135 if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, 136 sizeof(Info), NULL, NULL)) != ZX_OK) { 137 Printf("libFuzzer: unable to get info about self: %s\n", 138 _zx_status_get_string(rc)); 139 exit(1); 140 } 141 return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20; 142 } 143 144 template <typename Fn> 145 class RunOnDestruction { 146 public: 147 explicit RunOnDestruction(Fn fn) : fn_(fn) {} 148 ~RunOnDestruction() { fn_(); } 149 150 private: 151 Fn fn_; 152 }; 153 154 template <typename Fn> 155 RunOnDestruction<Fn> at_scope_exit(Fn fn) { 156 return RunOnDestruction<Fn>(fn); 157 } 158 159 int ExecuteCommand(const Command &Cmd) { 160 zx_status_t rc; 161 162 // Convert arguments to C array 163 auto Args = Cmd.getArguments(); 164 size_t Argc = Args.size(); 165 assert(Argc != 0); 166 std::unique_ptr<const char *[]> Argv(new const char *[Argc]); 167 for (size_t i = 0; i < Argc; ++i) 168 Argv[i] = Args[i].c_str(); 169 170 // Create the basic launchpad. Clone everything except stdio. 171 launchpad_t *lp; 172 launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp); 173 launchpad_load_from_file(lp, Argv[0]); 174 launchpad_set_args(lp, Argc, Argv.get()); 175 launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO)); 176 177 // Determine stdout 178 int FdOut = STDOUT_FILENO; 179 180 if (Cmd.hasOutputFile()) { 181 auto Filename = Cmd.getOutputFile(); 182 FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); 183 if (FdOut == -1) { 184 Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(), 185 strerror(errno)); 186 return ZX_ERR_IO; 187 } 188 } 189 auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } ); 190 191 // Determine stderr 192 int FdErr = STDERR_FILENO; 193 if (Cmd.isOutAndErrCombined()) 194 FdErr = FdOut; 195 196 // Clone the file descriptors into the new process 197 if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK || 198 (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK || 199 (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) { 200 Printf("libFuzzer: failed to clone FDIO: %s\n", _zx_status_get_string(rc)); 201 return rc; 202 } 203 204 // Start the process 205 zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; 206 const char *ErrorMsg = nullptr; 207 if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) { 208 Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg, 209 _zx_status_get_string(rc)); 210 return rc; 211 } 212 auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); }); 213 214 // Now join the process and return the exit status. 215 if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, 216 ZX_TIME_INFINITE, nullptr)) != ZX_OK) { 217 Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], 218 _zx_status_get_string(rc)); 219 return rc; 220 } 221 222 zx_info_process_t Info; 223 if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, 224 sizeof(Info), nullptr, nullptr)) != ZX_OK) { 225 Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0], 226 zx_status_get_string(rc)); 227 return rc; 228 } 229 230 return Info.return_code; 231 } 232 233 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 234 size_t PattLen) { 235 return memmem(Data, DataLen, Patt, PattLen); 236 } 237 238 } // namespace fuzzer 239 240 #endif // LIBFUZZER_FUCHSIA 241