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 "FuzzerPlatform.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/fdio.h> |
22 | #include <lib/fdio/spawn.h> |
23 | #include <string> |
24 | #include <sys/select.h> |
25 | #include <thread> |
26 | #include <unistd.h> |
27 | #include <zircon/errors.h> |
28 | #include <zircon/process.h> |
29 | #include <zircon/sanitizer.h> |
30 | #include <zircon/status.h> |
31 | #include <zircon/syscalls.h> |
32 | #include <zircon/syscalls/debug.h> |
33 | #include <zircon/syscalls/exception.h> |
34 | #include <zircon/syscalls/object.h> |
35 | #include <zircon/types.h> |
36 | |
37 | #include <vector> |
38 | |
39 | namespace fuzzer { |
40 | |
41 | // Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written |
42 | // around, the general approach is to spin up dedicated threads to watch for |
43 | // each requested condition (alarm, interrupt, crash). Of these, the crash |
44 | // handler is the most involved, as it requires resuming the crashed thread in |
45 | // order to invoke the sanitizers to get the needed state. |
46 | |
47 | // Forward declaration of assembly trampoline needed to resume crashed threads. |
48 | // This appears to have external linkage to C++, which is why it's not in the |
49 | // anonymous namespace. The assembly definition inside MakeTrampoline() |
50 | // actually defines the symbol with internal linkage only. |
51 | void CrashTrampolineAsm() __asm__("CrashTrampolineAsm" ); |
52 | |
53 | namespace { |
54 | |
55 | // The signal handler thread uses Zircon exceptions to resume crashed threads |
56 | // into libFuzzer's POSIX signal handlers. The associated event is used to |
57 | // signal when the thread is running, and when it should stop. |
58 | std::thread SignalHandler; |
59 | zx_handle_t SignalHandlerEvent = ZX_HANDLE_INVALID; |
60 | |
61 | // Helper function to handle Zircon syscall failures. |
62 | void ExitOnErr(zx_status_t Status, const char *Syscall) { |
63 | if (Status != ZX_OK) { |
64 | Printf("libFuzzer: %s failed: %s\n" , Syscall, |
65 | _zx_status_get_string(Status)); |
66 | exit(1); |
67 | } |
68 | } |
69 | |
70 | void AlarmHandler(int Seconds) { |
71 | while (true) { |
72 | SleepSeconds(Seconds); |
73 | Fuzzer::StaticAlarmCallback(); |
74 | } |
75 | } |
76 | |
77 | // For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback |
78 | // without POSIX signal handlers. To achieve this, we use an assembly function |
79 | // to add the necessary CFI unwinding information and a C function to bridge |
80 | // from that back into C++. |
81 | |
82 | // FIXME: This works as a short-term solution, but this code really shouldn't be |
83 | // architecture dependent. A better long term solution is to implement remote |
84 | // unwinding and expose the necessary APIs through sanitizer_common and/or ASAN |
85 | // to allow the exception handling thread to gather the crash state directly. |
86 | // |
87 | // Alternatively, Fuchsia may in future actually implement basic signal |
88 | // handling for the machine trap signals. |
89 | #if defined(__x86_64__) |
90 | |
91 | #define FOREACH_REGISTER(OP_REG, OP_NUM) \ |
92 | OP_REG(rax) \ |
93 | OP_REG(rbx) \ |
94 | OP_REG(rcx) \ |
95 | OP_REG(rdx) \ |
96 | OP_REG(rsi) \ |
97 | OP_REG(rdi) \ |
98 | OP_REG(rbp) \ |
99 | OP_REG(rsp) \ |
100 | OP_REG(r8) \ |
101 | OP_REG(r9) \ |
102 | OP_REG(r10) \ |
103 | OP_REG(r11) \ |
104 | OP_REG(r12) \ |
105 | OP_REG(r13) \ |
106 | OP_REG(r14) \ |
107 | OP_REG(r15) \ |
108 | OP_REG(rip) |
109 | |
110 | #elif defined(__aarch64__) |
111 | |
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_REG(sp) |
144 | |
145 | #elif defined(__riscv) |
146 | |
147 | #define FOREACH_REGISTER(OP_REG, OP_NUM) \ |
148 | OP_REG(ra) \ |
149 | OP_REG(sp) \ |
150 | OP_REG(gp) \ |
151 | OP_REG(tp) \ |
152 | OP_REG(t0) \ |
153 | OP_REG(t1) \ |
154 | OP_REG(t2) \ |
155 | OP_REG(s0) \ |
156 | OP_REG(s1) \ |
157 | OP_REG(a0) \ |
158 | OP_REG(a1) \ |
159 | OP_REG(a2) \ |
160 | OP_REG(a3) \ |
161 | OP_REG(a4) \ |
162 | OP_REG(a5) \ |
163 | OP_REG(a6) \ |
164 | OP_REG(a7) \ |
165 | OP_REG(s2) \ |
166 | OP_REG(s3) \ |
167 | OP_REG(s4) \ |
168 | OP_REG(s5) \ |
169 | OP_REG(s6) \ |
170 | OP_REG(s7) \ |
171 | OP_REG(s8) \ |
172 | OP_REG(s9) \ |
173 | OP_REG(s10) \ |
174 | OP_REG(s11) \ |
175 | OP_REG(t3) \ |
176 | OP_REG(t4) \ |
177 | OP_REG(t5) \ |
178 | OP_REG(t6) \ |
179 | |
180 | #else |
181 | #error "Unsupported architecture for fuzzing on Fuchsia" |
182 | #endif |
183 | |
184 | // Produces a CFI directive for the named or numbered register. |
185 | // The value used refers to an assembler immediate operand with the same name |
186 | // as the register (see ASM_OPERAND_REG). |
187 | #define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n" |
188 | #define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(x##num) |
189 | |
190 | // Produces an assembler immediate operand for the named or numbered register. |
191 | // This operand contains the offset of the register relative to the CFA. |
192 | #define ASM_OPERAND_REG(reg) \ |
193 | [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg)), |
194 | #define ASM_OPERAND_NUM(num) \ |
195 | [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num])), |
196 | |
197 | // Trampoline to bridge from the assembly below to the static C++ crash |
198 | // callback. |
199 | __attribute__((noreturn)) |
200 | static void StaticCrashHandler() { |
201 | Fuzzer::StaticCrashSignalCallback(); |
202 | for (;;) { |
203 | _Exit(1); |
204 | } |
205 | } |
206 | |
207 | // This trampoline function has the necessary CFI information to unwind |
208 | // and get a backtrace: |
209 | // * The stack contains a copy of all the registers at the point of crash, |
210 | // the code has CFI directives specifying how to restore them. |
211 | // * A call to StaticCrashHandler, which will print the stacktrace and exit |
212 | // the fuzzer, generating a crash artifact. |
213 | // |
214 | // The __attribute__((used)) is necessary because the function |
215 | // is never called; it's just a container around the assembly to allow it to |
216 | // use operands for compile-time computed constants. |
217 | __attribute__((used)) |
218 | void MakeTrampoline() { |
219 | __asm__( |
220 | ".cfi_endproc\n" |
221 | ".pushsection .text.CrashTrampolineAsm\n" |
222 | ".type CrashTrampolineAsm,STT_FUNC\n" |
223 | "CrashTrampolineAsm:\n" |
224 | ".cfi_startproc simple\n" |
225 | ".cfi_signal_frame\n" |
226 | #if defined(__x86_64__) |
227 | ".cfi_return_column rip\n" |
228 | ".cfi_def_cfa rsp, 0\n" |
229 | FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) |
230 | "call %c[StaticCrashHandler]\n" |
231 | "ud2\n" |
232 | #elif defined(__aarch64__) |
233 | ".cfi_return_column 33\n" |
234 | ".cfi_def_cfa sp, 0\n" |
235 | FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) |
236 | ".cfi_offset 33, %c[pc]\n" |
237 | ".cfi_offset 30, %c[lr]\n" |
238 | "bl %c[StaticCrashHandler]\n" |
239 | "brk 1\n" |
240 | #elif defined(__riscv) |
241 | ".cfi_return_column 64\n" |
242 | ".cfi_def_cfa sp, 0\n" |
243 | ".cfi_offset 64, %[pc]\n" |
244 | FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) |
245 | "call %c[StaticCrashHandler]\n" |
246 | "unimp\n" |
247 | #else |
248 | #error "Unsupported architecture for fuzzing on Fuchsia" |
249 | #endif |
250 | ".cfi_endproc\n" |
251 | ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" |
252 | ".popsection\n" |
253 | ".cfi_startproc\n" |
254 | : // No outputs |
255 | : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) |
256 | #if defined(__aarch64__) || defined(__riscv) |
257 | ASM_OPERAND_REG(pc) |
258 | #endif |
259 | #if defined(__aarch64__) |
260 | ASM_OPERAND_REG(lr) |
261 | #endif |
262 | [StaticCrashHandler] "i" (StaticCrashHandler)); |
263 | } |
264 | |
265 | void CrashHandler() { |
266 | assert(SignalHandlerEvent != ZX_HANDLE_INVALID); |
267 | |
268 | // This structure is used to ensure we close handles to objects we create in |
269 | // this handler. |
270 | struct ScopedHandle { |
271 | ~ScopedHandle() { _zx_handle_close(Handle); } |
272 | zx_handle_t Handle = ZX_HANDLE_INVALID; |
273 | }; |
274 | |
275 | // Create the exception channel. We need to claim to be a "debugger" so the |
276 | // kernel will allow us to modify and resume dying threads (see below). Once |
277 | // the channel is set, we can signal the main thread to continue and wait |
278 | // for the exception to arrive. |
279 | ScopedHandle Channel; |
280 | zx_handle_t Self = _zx_process_self(); |
281 | ExitOnErr(_zx_task_create_exception_channel( |
282 | Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle), |
283 | "_zx_task_create_exception_channel" ); |
284 | |
285 | ExitOnErr(_zx_object_signal(SignalHandlerEvent, 0, ZX_USER_SIGNAL_0), |
286 | "_zx_object_signal" ); |
287 | |
288 | // This thread lives as long as the process in order to keep handling |
289 | // crashes. In practice, the first crashed thread to reach the end of the |
290 | // StaticCrashHandler will end the process. |
291 | while (true) { |
292 | zx_wait_item_t WaitItems[] = { |
293 | { |
294 | .handle = SignalHandlerEvent, |
295 | .waitfor = ZX_USER_SIGNAL_1, |
296 | .pending = 0, |
297 | }, |
298 | { |
299 | .handle = Channel.Handle, |
300 | .waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, |
301 | .pending = 0, |
302 | }, |
303 | }; |
304 | auto Status = _zx_object_wait_many( |
305 | WaitItems, sizeof(WaitItems) / sizeof(WaitItems[0]), ZX_TIME_INFINITE); |
306 | if (Status != ZX_OK || (WaitItems[1].pending & ZX_CHANNEL_READABLE) == 0) { |
307 | break; |
308 | } |
309 | |
310 | zx_exception_info_t ExceptionInfo; |
311 | ScopedHandle Exception; |
312 | ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo, |
313 | &Exception.Handle, sizeof(ExceptionInfo), 1, |
314 | nullptr, nullptr), |
315 | "_zx_channel_read" ); |
316 | |
317 | // Ignore informational synthetic exceptions. |
318 | if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type || |
319 | ZX_EXCP_THREAD_EXITING == ExceptionInfo.type || |
320 | ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) { |
321 | continue; |
322 | } |
323 | |
324 | // At this point, we want to get the state of the crashing thread, but |
325 | // libFuzzer and the sanitizers assume this will happen from that same |
326 | // thread via a POSIX signal handler. "Resurrecting" the thread in the |
327 | // middle of the appropriate callback is as simple as forcibly setting the |
328 | // instruction pointer/program counter, provided we NEVER EVER return from |
329 | // that function (since otherwise our stack will not be valid). |
330 | ScopedHandle Thread; |
331 | ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle), |
332 | "_zx_exception_get_thread" ); |
333 | |
334 | zx_thread_state_general_regs_t GeneralRegisters; |
335 | ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, |
336 | &GeneralRegisters, |
337 | sizeof(GeneralRegisters)), |
338 | "_zx_thread_read_state" ); |
339 | |
340 | // To unwind properly, we need to push the crashing thread's register state |
341 | // onto the stack and jump into a trampoline with CFI instructions on how |
342 | // to restore it. |
343 | #if defined(__x86_64__) |
344 | |
345 | uintptr_t StackPtr = |
346 | (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) & |
347 | -(uintptr_t)16; |
348 | __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, |
349 | sizeof(GeneralRegisters)); |
350 | GeneralRegisters.rsp = StackPtr; |
351 | GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); |
352 | |
353 | #elif defined(__aarch64__) || defined(__riscv) |
354 | |
355 | uintptr_t StackPtr = |
356 | (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16; |
357 | __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters, |
358 | sizeof(GeneralRegisters)); |
359 | GeneralRegisters.sp = StackPtr; |
360 | GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm); |
361 | |
362 | #else |
363 | #error "Unsupported architecture for fuzzing on Fuchsia" |
364 | #endif |
365 | |
366 | // Now force the crashing thread's state. |
367 | ExitOnErr( |
368 | _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS, |
369 | &GeneralRegisters, sizeof(GeneralRegisters)), |
370 | "_zx_thread_write_state" ); |
371 | |
372 | // Set the exception to HANDLED so it resumes the thread on close. |
373 | uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED; |
374 | ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE, |
375 | &ExceptionState, sizeof(ExceptionState)), |
376 | "zx_object_set_property" ); |
377 | } |
378 | } |
379 | |
380 | void StopSignalHandler() { |
381 | _zx_object_signal(SignalHandlerEvent, 0, ZX_USER_SIGNAL_1); |
382 | if (SignalHandler.joinable()) { |
383 | SignalHandler.join(); |
384 | } |
385 | _zx_handle_close(SignalHandlerEvent); |
386 | } |
387 | |
388 | } // namespace |
389 | |
390 | // Platform specific functions. |
391 | void SetSignalHandler(const FuzzingOptions &Options) { |
392 | // Make sure information from libFuzzer and the sanitizers are easy to |
393 | // reassemble. `__sanitizer_log_write` has the added benefit of ensuring the |
394 | // DSO map is always available for the symbolizer. |
395 | // A uint64_t fits in 20 chars, so 64 is plenty. |
396 | char Buf[64]; |
397 | memset(Buf, 0, sizeof(Buf)); |
398 | snprintf(Buf, sizeof(Buf), "==%lu== INFO: libFuzzer starting.\n" , GetPid()); |
399 | if (EF->__sanitizer_log_write) |
400 | __sanitizer_log_write(Buf, sizeof(Buf)); |
401 | Printf("%s" , Buf); |
402 | |
403 | // Set up alarm handler if needed. |
404 | if (Options.HandleAlrm && Options.UnitTimeoutSec > 0) { |
405 | std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1); |
406 | T.detach(); |
407 | } |
408 | |
409 | // Options.HandleInt and Options.HandleTerm are not supported on Fuchsia |
410 | |
411 | // Early exit if no crash handler needed. |
412 | if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll && |
413 | !Options.HandleFpe && !Options.HandleAbrt) |
414 | return; |
415 | |
416 | // Set up the crash handler and wait until it is ready before proceeding. |
417 | ExitOnErr(_zx_event_create(0, &SignalHandlerEvent), "_zx_event_create" ); |
418 | |
419 | SignalHandler = std::thread(CrashHandler); |
420 | zx_status_t Status = _zx_object_wait_one(SignalHandlerEvent, ZX_USER_SIGNAL_0, |
421 | ZX_TIME_INFINITE, nullptr); |
422 | ExitOnErr(Status, "_zx_object_wait_one" ); |
423 | |
424 | std::atexit(StopSignalHandler); |
425 | } |
426 | |
427 | void SleepSeconds(int Seconds) { |
428 | _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds))); |
429 | } |
430 | |
431 | unsigned long GetPid() { |
432 | zx_status_t rc; |
433 | zx_info_handle_basic_t Info; |
434 | if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info, |
435 | sizeof(Info), NULL, NULL)) != ZX_OK) { |
436 | Printf("libFuzzer: unable to get info about self: %s\n" , |
437 | _zx_status_get_string(rc)); |
438 | exit(1); |
439 | } |
440 | return Info.koid; |
441 | } |
442 | |
443 | size_t GetPeakRSSMb() { |
444 | zx_status_t rc; |
445 | zx_info_task_stats_t Info; |
446 | if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info, |
447 | sizeof(Info), NULL, NULL)) != ZX_OK) { |
448 | Printf("libFuzzer: unable to get info about self: %s\n" , |
449 | _zx_status_get_string(rc)); |
450 | exit(1); |
451 | } |
452 | return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20; |
453 | } |
454 | |
455 | template <typename Fn> |
456 | class RunOnDestruction { |
457 | public: |
458 | explicit RunOnDestruction(Fn fn) : fn_(fn) {} |
459 | ~RunOnDestruction() { fn_(); } |
460 | |
461 | private: |
462 | Fn fn_; |
463 | }; |
464 | |
465 | template <typename Fn> |
466 | RunOnDestruction<Fn> at_scope_exit(Fn fn) { |
467 | return RunOnDestruction<Fn>(fn); |
468 | } |
469 | |
470 | static fdio_spawn_action_t clone_fd_action(int localFd, int targetFd) { |
471 | return { |
472 | .action = FDIO_SPAWN_ACTION_CLONE_FD, |
473 | .fd = |
474 | { |
475 | .local_fd = localFd, |
476 | .target_fd = targetFd, |
477 | }, |
478 | }; |
479 | } |
480 | |
481 | int ExecuteCommand(const Command &Cmd) { |
482 | zx_status_t rc; |
483 | |
484 | // Convert arguments to C array |
485 | auto Args = Cmd.getArguments(); |
486 | size_t Argc = Args.size(); |
487 | assert(Argc != 0); |
488 | std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]); |
489 | for (size_t i = 0; i < Argc; ++i) |
490 | Argv[i] = Args[i].c_str(); |
491 | Argv[Argc] = nullptr; |
492 | |
493 | // Determine output. On Fuchsia, the fuzzer is typically run as a component |
494 | // that lacks a mutable working directory. Fortunately, when this is the case |
495 | // a mutable output directory must be specified using "-artifact_prefix=...", |
496 | // so write the log file(s) there. |
497 | // However, we don't want to apply this logic for absolute paths. |
498 | int FdOut = STDOUT_FILENO; |
499 | bool discardStdout = false; |
500 | bool discardStderr = false; |
501 | |
502 | if (Cmd.hasOutputFile()) { |
503 | std::string Path = Cmd.getOutputFile(); |
504 | if (Path == getDevNull()) { |
505 | // On Fuchsia, there's no "/dev/null" like-file, so we |
506 | // just don't copy the FDs into the spawned process. |
507 | discardStdout = true; |
508 | } else { |
509 | bool IsAbsolutePath = Path.length() > 1 && Path[0] == '/'; |
510 | if (!IsAbsolutePath && Cmd.hasFlag("artifact_prefix" )) |
511 | Path = Cmd.getFlagValue("artifact_prefix" ) + "/" + Path; |
512 | |
513 | FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0); |
514 | if (FdOut == -1) { |
515 | Printf("libFuzzer: failed to open %s: %s\n" , Path.c_str(), |
516 | strerror(errno)); |
517 | return ZX_ERR_IO; |
518 | } |
519 | } |
520 | } |
521 | auto CloseFdOut = at_scope_exit([FdOut]() { |
522 | if (FdOut != STDOUT_FILENO) |
523 | close(FdOut); |
524 | }); |
525 | |
526 | // Determine stderr |
527 | int FdErr = STDERR_FILENO; |
528 | if (Cmd.isOutAndErrCombined()) { |
529 | FdErr = FdOut; |
530 | if (discardStdout) |
531 | discardStderr = true; |
532 | } |
533 | |
534 | // Clone the file descriptors into the new process |
535 | std::vector<fdio_spawn_action_t> SpawnActions; |
536 | SpawnActions.push_back(clone_fd_action(STDIN_FILENO, STDIN_FILENO)); |
537 | |
538 | if (!discardStdout) |
539 | SpawnActions.push_back(clone_fd_action(FdOut, STDOUT_FILENO)); |
540 | if (!discardStderr) |
541 | SpawnActions.push_back(clone_fd_action(FdErr, STDERR_FILENO)); |
542 | |
543 | // Start the process. |
544 | char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; |
545 | zx_handle_t ProcessHandle = ZX_HANDLE_INVALID; |
546 | rc = fdio_spawn_etc(ZX_HANDLE_INVALID, |
547 | FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), Argv[0], |
548 | Argv.get(), nullptr, SpawnActions.size(), |
549 | SpawnActions.data(), &ProcessHandle, ErrorMsg); |
550 | |
551 | if (rc != ZX_OK) { |
552 | Printf("libFuzzer: failed to launch '%s': %s, %s\n" , Argv[0], ErrorMsg, |
553 | _zx_status_get_string(rc)); |
554 | return rc; |
555 | } |
556 | auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); }); |
557 | |
558 | // Now join the process and return the exit status. |
559 | if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED, |
560 | ZX_TIME_INFINITE, nullptr)) != ZX_OK) { |
561 | Printf("libFuzzer: failed to join '%s': %s\n" , Argv[0], |
562 | _zx_status_get_string(rc)); |
563 | return rc; |
564 | } |
565 | |
566 | zx_info_process_t Info; |
567 | if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info, |
568 | sizeof(Info), nullptr, nullptr)) != ZX_OK) { |
569 | Printf("libFuzzer: unable to get return code from '%s': %s\n" , Argv[0], |
570 | _zx_status_get_string(rc)); |
571 | return rc; |
572 | } |
573 | |
574 | return static_cast<int>(Info.return_code); |
575 | } |
576 | |
577 | bool ExecuteCommand(const Command &BaseCmd, std::string *CmdOutput) { |
578 | auto LogFilePath = TempPath("SimPopenOut" , ".txt" ); |
579 | Command Cmd(BaseCmd); |
580 | Cmd.setOutputFile(LogFilePath); |
581 | int Ret = ExecuteCommand(Cmd); |
582 | *CmdOutput = FileToString(LogFilePath); |
583 | RemoveFile(LogFilePath); |
584 | return Ret == 0; |
585 | } |
586 | |
587 | const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, |
588 | size_t PattLen) { |
589 | return memmem(Data, DataLen, Patt, PattLen); |
590 | } |
591 | |
592 | // In fuchsia, accessing /dev/null is not supported. There's nothing |
593 | // similar to a file that discards everything that is written to it. |
594 | // The way of doing something similar in fuchsia is by using |
595 | // fdio_null_create and binding that to a file descriptor. |
596 | void DiscardOutput(int Fd) { |
597 | fdio_t *fdio_null = fdio_null_create(); |
598 | if (fdio_null == nullptr) return; |
599 | int nullfd = fdio_bind_to_fd(fdio_null, -1, 0); |
600 | if (nullfd < 0) return; |
601 | dup2(nullfd, Fd); |
602 | } |
603 | |
604 | size_t PageSize() { |
605 | static size_t PageSizeCached = _zx_system_get_page_size(); |
606 | return PageSizeCached; |
607 | } |
608 | |
609 | void SetThreadName(std::thread &thread, const std::string &name) { |
610 | // TODO ? |
611 | } |
612 | |
613 | } // namespace fuzzer |
614 | |
615 | #endif // LIBFUZZER_FUCHSIA |
616 | |