aboutsummaryrefslogtreecommitdiff
path: root/lib/fuzzer/FuzzerUtilFuchsia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuzzer/FuzzerUtilFuchsia.cpp')
-rw-r--r--lib/fuzzer/FuzzerUtilFuchsia.cpp143
1 files changed, 82 insertions, 61 deletions
diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp
index cd48fefef352..1f04b33c154e 100644
--- a/lib/fuzzer/FuzzerUtilFuchsia.cpp
+++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -1,9 +1,8 @@
//===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Misc utils implementation using Fuchsia/Zircon APIs.
@@ -14,6 +13,7 @@
#include "FuzzerInternal.h"
#include "FuzzerUtil.h"
+#include <cassert>
#include <cerrno>
#include <cinttypes>
#include <cstdint>
@@ -30,7 +30,7 @@
#include <zircon/syscalls.h>
#include <zircon/syscalls/debug.h>
#include <zircon/syscalls/exception.h>
-#include <zircon/syscalls/port.h>
+#include <zircon/syscalls/object.h>
#include <zircon/types.h>
namespace fuzzer {
@@ -49,10 +49,6 @@ void CrashTrampolineAsm() __asm__("CrashTrampolineAsm");
namespace {
-// A magic value for the Zircon exception port, chosen to spell 'FUZZING'
-// when interpreted as a byte sequence on little-endian platforms.
-const uint64_t kFuzzingCrash = 0x474e495a5a5546;
-
// Helper function to handle Zircon syscall failures.
void ExitOnErr(zx_status_t Status, const char *Syscall) {
if (Status != ZX_OK) {
@@ -218,76 +214,101 @@ void CrashHandler(zx_handle_t *Event) {
zx_handle_t Handle = ZX_HANDLE_INVALID;
};
- // Create and bind the exception port. We need to claim to be a "debugger" so
- // the kernel will allow us to modify and resume dying threads (see below).
- // Once the port is set, we can signal the main thread to continue and wait
+ // Create the exception channel. We need to claim to be a "debugger" so the
+ // kernel will allow us to modify and resume dying threads (see below). Once
+ // the channel is set, we can signal the main thread to continue and wait
// for the exception to arrive.
- ScopedHandle Port;
- ExitOnErr(_zx_port_create(0, &Port.Handle), "_zx_port_create");
+ ScopedHandle Channel;
zx_handle_t Self = _zx_process_self();
-
- ExitOnErr(_zx_task_bind_exception_port(Self, Port.Handle, kFuzzingCrash,
- ZX_EXCEPTION_PORT_DEBUGGER),
- "_zx_task_bind_exception_port");
+ ExitOnErr(_zx_task_create_exception_channel(
+ Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle),
+ "_zx_task_create_exception_channel");
ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0),
"_zx_object_signal");
- zx_port_packet_t Packet;
- ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE, &Packet),
- "_zx_port_wait");
-
- // At this point, we want to get the state of the crashing thread, but
- // libFuzzer and the sanitizers assume this will happen from that same thread
- // via a POSIX signal handler. "Resurrecting" the thread in the middle of the
- // appropriate callback is as simple as forcibly setting the instruction
- // pointer/program counter, provided we NEVER EVER return from that function
- // (since otherwise our stack will not be valid).
- ScopedHandle Thread;
- ExitOnErr(_zx_object_get_child(Self, Packet.exception.tid,
- ZX_RIGHT_SAME_RIGHTS, &Thread.Handle),
- "_zx_object_get_child");
-
- zx_thread_state_general_regs_t GeneralRegisters;
- ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
- &GeneralRegisters, sizeof(GeneralRegisters)),
- "_zx_thread_read_state");
-
- // To unwind properly, we need to push the crashing thread's register state
- // onto the stack and jump into a trampoline with CFI instructions on how
- // to restore it.
+ // This thread lives as long as the process in order to keep handling
+ // crashes. In practice, the first crashed thread to reach the end of the
+ // StaticCrashHandler will end the process.
+ while (true) {
+ ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE,
+ ZX_TIME_INFINITE, nullptr),
+ "_zx_object_wait_one");
+
+ zx_exception_info_t ExceptionInfo;
+ ScopedHandle Exception;
+ ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo,
+ &Exception.Handle, sizeof(ExceptionInfo), 1,
+ nullptr, nullptr),
+ "_zx_channel_read");
+
+ // Ignore informational synthetic exceptions.
+ if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type ||
+ ZX_EXCP_THREAD_EXITING == ExceptionInfo.type ||
+ ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) {
+ continue;
+ }
+
+ // At this point, we want to get the state of the crashing thread, but
+ // libFuzzer and the sanitizers assume this will happen from that same
+ // thread via a POSIX signal handler. "Resurrecting" the thread in the
+ // middle of the appropriate callback is as simple as forcibly setting the
+ // instruction pointer/program counter, provided we NEVER EVER return from
+ // that function (since otherwise our stack will not be valid).
+ ScopedHandle Thread;
+ ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle),
+ "_zx_exception_get_thread");
+
+ zx_thread_state_general_regs_t GeneralRegisters;
+ ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
+ &GeneralRegisters,
+ sizeof(GeneralRegisters)),
+ "_zx_thread_read_state");
+
+ // To unwind properly, we need to push the crashing thread's register state
+ // onto the stack and jump into a trampoline with CFI instructions on how
+ // to restore it.
#if defined(__x86_64__)
- uintptr_t StackPtr =
- (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) &
- -(uintptr_t)16;
- __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
- sizeof(GeneralRegisters));
- GeneralRegisters.rsp = StackPtr;
- GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
+ uintptr_t StackPtr =
+ (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) &
+ -(uintptr_t)16;
+ __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
+ sizeof(GeneralRegisters));
+ GeneralRegisters.rsp = StackPtr;
+ GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
#elif defined(__aarch64__)
- uintptr_t StackPtr =
- (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16;
- __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
- sizeof(GeneralRegisters));
- GeneralRegisters.sp = StackPtr;
- GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
+ uintptr_t StackPtr =
+ (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16;
+ __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
+ sizeof(GeneralRegisters));
+ GeneralRegisters.sp = StackPtr;
+ GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
#else
#error "Unsupported architecture for fuzzing on Fuchsia"
#endif
- // Now force the crashing thread's state.
- ExitOnErr(_zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
- &GeneralRegisters, sizeof(GeneralRegisters)),
- "_zx_thread_write_state");
-
- ExitOnErr(_zx_task_resume_from_exception(Thread.Handle, Port.Handle, 0),
- "_zx_task_resume_from_exception");
+ // Now force the crashing thread's state.
+ ExitOnErr(
+ _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
+ &GeneralRegisters, sizeof(GeneralRegisters)),
+ "_zx_thread_write_state");
+
+ // Set the exception to HANDLED so it resumes the thread on close.
+ uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED;
+ ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE,
+ &ExceptionState, sizeof(ExceptionState)),
+ "zx_object_set_property");
+ }
}
} // namespace
+bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
+ return false; // UNIMPLEMENTED
+}
+
// Platform specific functions.
void SetSignalHandler(const FuzzingOptions &Options) {
// Set up alarm handler if needed.