1 //===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // Misc utils implementation using Fuchsia/Zircon APIs. 9 //===----------------------------------------------------------------------===// 10 #include "FuzzerDefs.h" 11 12 #if LIBFUZZER_FUCHSIA 13 14 #include "FuzzerInternal.h" 15 #include "FuzzerUtil.h" 16 #include <cassert> 17 #include <cerrno> 18 #include <cinttypes> 19 #include <cstdint> 20 #include <fcntl.h> 21 #include <lib/fdio/spawn.h> 22 #include <string> 23 #include <sys/select.h> 24 #include <thread> 25 #include <unistd.h> 26 #include <zircon/errors.h> 27 #include <zircon/process.h> 28 #include <zircon/sanitizer.h> 29 #include <zircon/status.h> 30 #include <zircon/syscalls.h> 31 #include <zircon/syscalls/debug.h> 32 #include <zircon/syscalls/exception.h> 33 #include <zircon/syscalls/object.h> 34 #include <zircon/types.h> 35 36 namespace fuzzer { 37 38 // Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written 39 // around, the general approach is to spin up dedicated threads to watch for 40 // each requested condition (alarm, interrupt, crash). Of these, the crash 41 // handler is the most involved, as it requires resuming the crashed thread in 42 // order to invoke the sanitizers to get the needed state. 43 44 // Forward declaration of assembly trampoline needed to resume crashed threads. 45 // This appears to have external linkage to C++, which is why it's not in the 46 // anonymous namespace. The assembly definition inside MakeTrampoline() 47 // actually defines the symbol with internal linkage only. 48 void CrashTrampolineAsm() __asm__("CrashTrampolineAsm"); 49 50 namespace { 51 52 // Helper function to handle Zircon syscall failures. 53 void ExitOnErr(zx_status_t Status, const char *Syscall) { 54 if (Status != ZX_OK) { 55 Printf("libFuzzer: %s failed: %s\n", Syscall, 56 _zx_status_get_string(Status)); 57 exit(1); 58 } 59 } 60 61 void AlarmHandler(int Seconds) { 62 while (true) { 63 SleepSeconds(Seconds); 64 Fuzzer::StaticAlarmCallback(); 65 } 66 } 67 68 void InterruptHandler() { 69 fd_set readfds; 70 // Ctrl-C sends ETX in Zircon. 71 do { 72 FD_ZERO(&readfds); 73 FD_SET(STDIN_FILENO, &readfds); 74 select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr); 75 } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03); 76 Fuzzer::StaticInterruptCallback(); 77 } 78 79 // For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback 80 // without POSIX signal handlers. To achieve this, we use an assembly function 81 // to add the necessary CFI unwinding information and a C function to bridge 82 // from that back into C++. 83 84 // FIXME: This works as a short-term solution, but this code really shouldn't be 85 // architecture dependent. A better long term solution is to implement remote 86 // unwinding and expose the necessary APIs through sanitizer_common and/or ASAN 87 // to allow the exception handling thread to gather the crash state directly. 88 // 89 // Alternatively, Fuchsia may in future actually implement basic signal 90 // handling for the machine trap signals. 91 #if defined(__x86_64__) 92 #define FOREACH_REGISTER(OP_REG, OP_NUM) \ 93 OP_REG(rax) \ 94 OP_REG(rbx) \ 95 OP_REG(rcx) \ 96 OP_REG(rdx) \ 97 OP_REG(rsi) \ 98 OP_REG(rdi) \ 99 OP_REG(rbp) \ 100 OP_REG(rsp) \ 101 OP_REG(r8) \ 102 OP_REG(r9) \ 103 OP_REG(r10) \ 104 OP_REG(r11) \ 105 OP_REG(r12) \ 106 OP_REG(r13) \ 107 OP_REG(r14) \ 108 OP_REG(r15) \ 109 OP_REG(rip) 110 111 #elif defined(__aarch64__) 112 #define FOREACH_REGISTER(OP_REG, OP_NUM) \ 113 OP_NUM(0) \ 114 OP_NUM(1) \ 115 OP_NUM(2) \ 116 OP_NUM(3) \ 117 OP_NUM(4) \ 118 OP_NUM(5) \ 119 OP_NUM(6) \ 120 OP_NUM(7) \ 121 OP_NUM(8) \ 122 OP_NUM(9) \ 123 OP_NUM(10) \ 124 OP_NUM(11) \ 125 OP_NUM(12) \ 126 OP_NUM(13) \ 127 OP_NUM(14) \ 128 OP_NUM(15) \ 129 OP_NUM(16) \ 130 OP_NUM(17) \ 131 OP_NUM(18) \ 132 OP_NUM(19) \ 133 OP_NUM(20) \ 134 OP_NUM(21) \ 135 OP_NUM(22) \ 136 OP_NUM(23) \ 137 OP_NUM(24) \ 138 OP_NUM(25) \ 139 OP_NUM(26) \ 140 OP_NUM(27) \ 141 OP_NUM(28) \ 142 OP_NUM(29) \ 143 OP_NUM(30) \ 144 OP_REG(sp) 145 146 #else 147 #error "Unsupported architecture for fuzzing on Fuchsia" 148 #endif 149 150 // Produces a CFI directive for the named or numbered register. 151 #define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n" 152 #define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(r##num) 153 154 // Produces an assembler input operand for the named or numbered register. 155 #define ASM_OPERAND_REG(reg) \ 156 [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg)), 157 #define ASM_OPERAND_NUM(num) \ 158 [r##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num])), 159 160 // Trampoline to bridge from the assembly below to the static C++ crash 161 // callback. 162 __attribute__((noreturn)) 163 static void StaticCrashHandler() { 164 Fuzzer::StaticCrashSignalCallback(); 165 for (;;) { 166 _Exit(1); 167 } 168 } 169 170 // Creates the trampoline with the necessary CFI information to unwind through 171 // to the crashing call stack. The attribute is necessary because the function 172 // is never called; it's just a container around the assembly to allow it to 173 // use operands for compile-time computed constants. 174 __attribute__((used)) 175 void MakeTrampoline() { 176 __asm__(".cfi_endproc\n" 177 ".pushsection .text.CrashTrampolineAsm\n" 178 ".type CrashTrampolineAsm,STT_FUNC\n" 179 "CrashTrampolineAsm:\n" 180 ".cfi_startproc simple\n" 181 ".cfi_signal_frame\n" 182 #if defined(__x86_64__) 183 ".cfi_return_column rip\n" 184 ".cfi_def_cfa rsp, 0\n" 185 FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) 186 "call %c[StaticCrashHandler]\n" 187 "ud2\n" 188 #elif defined(__aarch64__) 189 ".cfi_return_column 33\n" 190 ".cfi_def_cfa sp, 0\n" 191 ".cfi_offset 33, %c[pc]\n" 192 FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) 193 "bl %[StaticCrashHandler]\n" 194 #else 195 #error "Unsupported architecture for fuzzing on Fuchsia" 196 #endif 197 ".cfi_endproc\n" 198 ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" 199 ".popsection\n" 200 ".cfi_startproc\n" 201 : // No outputs 202 : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) 203 #if defined(__aarch64__) 204 ASM_OPERAND_REG(pc) 205 #endif 206 [StaticCrashHandler] "i" (StaticCrashHandler)); 207 } 208 209 void CrashHandler(zx_handle_t *Event) { 210 // This structure is used to ensure we close handles to objects we create in 211 // this handler. 212 struct ScopedHandle { 213 ~ScopedHandle() { _zx_handle_close(Handle); } 214 zx_handle_t Handle = ZX_HANDLE_INVALID; 215 }; 216 217 // Create the exception channel. We need to claim to be a "debugger" so the 218 // kernel will allow us to modify and resume dying threads (see below). Once 219 // the channel is set, we can signal the main thread to continue and wait 220 // for the exception to arrive. 221 ScopedHandle Channel; 222 zx_handle_t Self = _zx_process_self(); 223 ExitOnErr(_zx_task_create_exception_channel( 224 Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle), 225 "_zx_task_create_exception_channel"); 226 227 ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0), 228 "_zx_object_signal"); 229 230 // This thread lives as long as the process in order to keep handling 231 // crashes. In practice, the first crashed thread to reach the end of the 232 // StaticCrashHandler will end the process. 233 while (true) { 234 ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE, 235 ZX_TIME_INFINITE, nullptr), 236 "_zx_object_wait_one"); 237 238 zx_exception_info_t ExceptionInfo; 239 ScopedHandle Exception; 240 ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo, 241 &Exception.Handle, sizeof(ExceptionInfo), 1, 242 nullptr, nullptr), 243 "_zx_channel_read"); 244 245 // Ignore informational synthetic exceptions. 246 if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type || 247 ZX_EXCP_THREAD_EXITING == ExceptionInfo.type || 248 ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) { 249 continue; 250 } 251 252 // At this point, we want to get the state of the crashing thread, but 253 // libFuzzer and the sanitizers assume this will happen from that same 254 // thread via a POSIX signal handler. "Resurrecting" the thread in the 255 // middle of the appropriate callback is as simple as forcibly setting the 256 // instruction pointer/program counter, provided we NEVER EVER return from 257 // that function (since otherwise our stack will not be valid). 258 ScopedHandle Thread; 259 ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle), 260 "_zx_exception_get_thread"); 261 262 zx_thread_state_general_regs_t GeneralRegisters; 263 ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, 264 &GeneralRegisters, 265 sizeof(GeneralRegisters)), 266 "_zx_thread_read_state"); 267 268 // To unwind properly, we need to push the crashing thread's register state 269 // onto the stack and jump into a trampoline with CFI instructions on how 270 // to restore it. 271 #if defined(__x86_64__) 272 uintptr_t StackPtr = 273 (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) & 274 -(uintptr_t)16; 275 __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, 276 sizeof(GeneralRegisters)); 277 GeneralRegisters.rsp = StackPtr; 278 GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); 279 280 #elif defined(__aarch64__) 281 uintptr_t StackPtr = 282 (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16; 283 __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, 284 sizeof(GeneralRegisters)); 285 GeneralRegisters.sp = StackPtr; 286 GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); 287 288 #else 289 #error "Unsupported architecture for fuzzing on Fuchsia" 290 #endif 291 292 // Now force the crashing thread's state. 293 ExitOnErr( 294 _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, 295 &GeneralRegisters, sizeof(GeneralRegisters)), 296 "_zx_thread_write_state"); 297 298 // Set the exception to HANDLED so it resumes the thread on close. 299 uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED; 300 ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE, 301 &ExceptionState, sizeof(ExceptionState)), 302 "zx_object_set_property"); 303 } 304 } 305 306 } // namespace 307 308 bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) { 309 return false; // UNIMPLEMENTED 310 } 311 312 // Platform specific functions. 313 void SetSignalHandler(const FuzzingOptions &Options) { 314 // Set up alarm handler if needed. 315 if (Options.UnitTimeoutSec > 0) { 316 std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); 317 T.detach(); 318 } 319 320 // Set up interrupt handler if needed. 321 if (Options.HandleInt || Options.HandleTerm) { 322 std::thread T(InterruptHandler); 323 T.detach(); 324 } 325 326 // Early exit if no crash handler needed. 327 if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll && 328 !Options.HandleFpe && !Options.HandleAbrt) 329 return; 330 331 // Set up the crash handler and wait until it is ready before proceeding. 332 zx_handle_t Event; 333 ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create"); 334 335 std::thread T(CrashHandler, &Event); 336 zx_status_t Status = 337 _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr); 338 _zx_handle_close(Event); 339 ExitOnErr(Status, "_zx_object_wait_one"); 340 341 T.detach(); 342 } 343 344 void SleepSeconds(int Seconds) { 345 _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds))); 346 } 347 348 unsigned long GetPid() { 349 zx_status_t rc; 350 zx_info_handle_basic_t Info; 351 if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, 352 sizeof(Info), NULL, NULL)) != ZX_OK) { 353 Printf("libFuzzer: unable to get info about self: %s\n", 354 _zx_status_get_string(rc)); 355 exit(1); 356 } 357 return Info.koid; 358 } 359 360 size_t GetPeakRSSMb() { 361 zx_status_t rc; 362 zx_info_task_stats_t Info; 363 if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, 364 sizeof(Info), NULL, NULL)) != ZX_OK) { 365 Printf("libFuzzer: unable to get info about self: %s\n", 366 _zx_status_get_string(rc)); 367 exit(1); 368 } 369 return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20; 370 } 371 372 template <typename Fn> 373 class RunOnDestruction { 374 public: 375 explicit RunOnDestruction(Fn fn) : fn_(fn) {} 376 ~RunOnDestruction() { fn_(); } 377 378 private: 379 Fn fn_; 380 }; 381 382 template <typename Fn> 383 RunOnDestruction<Fn> at_scope_exit(Fn fn) { 384 return RunOnDestruction<Fn>(fn); 385 } 386 387 int ExecuteCommand(const Command &Cmd) { 388 zx_status_t rc; 389 390 // Convert arguments to C array 391 auto Args = Cmd.getArguments(); 392 size_t Argc = Args.size(); 393 assert(Argc != 0); 394 std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]); 395 for (size_t i = 0; i < Argc; ++i) 396 Argv[i] = Args[i].c_str(); 397 Argv[Argc] = nullptr; 398 399 // Determine output. On Fuchsia, the fuzzer is typically run as a component 400 // that lacks a mutable working directory. Fortunately, when this is the case 401 // a mutable output directory must be specified using "-artifact_prefix=...", 402 // so write the log file(s) there. 403 int FdOut = STDOUT_FILENO; 404 if (Cmd.hasOutputFile()) { 405 std::string Path; 406 if (Cmd.hasFlag("artifact_prefix")) 407 Path = Cmd.getFlagValue("artifact_prefix") + "/" + Cmd.getOutputFile(); 408 else 409 Path = Cmd.getOutputFile(); 410 FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); 411 if (FdOut == -1) { 412 Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(), 413 strerror(errno)); 414 return ZX_ERR_IO; 415 } 416 } 417 auto CloseFdOut = at_scope_exit([FdOut]() { 418 if (FdOut != STDOUT_FILENO) 419 close(FdOut); 420 }); 421 422 // Determine stderr 423 int FdErr = STDERR_FILENO; 424 if (Cmd.isOutAndErrCombined()) 425 FdErr = FdOut; 426 427 // Clone the file descriptors into the new process 428 fdio_spawn_action_t SpawnAction[] = { 429 { 430 .action = FDIO_SPAWN_ACTION_CLONE_FD, 431 .fd = 432 { 433 .local_fd = STDIN_FILENO, 434 .target_fd = STDIN_FILENO, 435 }, 436 }, 437 { 438 .action = FDIO_SPAWN_ACTION_CLONE_FD, 439 .fd = 440 { 441 .local_fd = FdOut, 442 .target_fd = STDOUT_FILENO, 443 }, 444 }, 445 { 446 .action = FDIO_SPAWN_ACTION_CLONE_FD, 447 .fd = 448 { 449 .local_fd = FdErr, 450 .target_fd = STDERR_FILENO, 451 }, 452 }, 453 }; 454 455 // Start the process. 456 char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 457 zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; 458 rc = fdio_spawn_etc( 459 ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), 460 Argv[0], Argv.get(), nullptr, 3, SpawnAction, &ProcessHandle, ErrorMsg); 461 if (rc != ZX_OK) { 462 Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg, 463 _zx_status_get_string(rc)); 464 return rc; 465 } 466 auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); }); 467 468 // Now join the process and return the exit status. 469 if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, 470 ZX_TIME_INFINITE, nullptr)) != ZX_OK) { 471 Printf("libFuzzer: failed to join '%s': %s\n", Argv[0], 472 _zx_status_get_string(rc)); 473 return rc; 474 } 475 476 zx_info_process_t Info; 477 if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, 478 sizeof(Info), nullptr, nullptr)) != ZX_OK) { 479 Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0], 480 _zx_status_get_string(rc)); 481 return rc; 482 } 483 484 return Info.return_code; 485 } 486 487 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 488 size_t PattLen) { 489 return memmem(Data, DataLen, Patt, PattLen); 490 } 491 492 } // namespace fuzzer 493 494 #endif // LIBFUZZER_FUCHSIA 495