diff --git a/zircon/public/gn/config/instrumentation/BUILD.gn b/zircon/public/gn/config/instrumentation/BUILD.gn index ada811bbae9cd39c50c4169150f28b490b24c48c..9ea97513bfe4c62f736c173eb68f68dd9d8131e1 100644 --- a/zircon/public/gn/config/instrumentation/BUILD.gn +++ b/zircon/public/gn/config/instrumentation/BUILD.gn @@ -113,6 +113,15 @@ if (toolchain.tags + [ "sancov" ] - [ "sancov" ] != toolchain.tags) { cflags = compiler_flags ldflags = compiler_flags } + + # This enables all the different kinds of sancov callbacks, not just + # the basic ones actually implemented by the canonical runtime. + config("sancov-full") { + compiler_flags = [ "-fsanitize-coverage=indirect-calls,trace-cmp,trace-div,trace-gep,trace-pc-guard,inline-8bit-counters,pc-table" ] + asmflags = compiler_flags + cflags = compiler_flags + ldflags = compiler_flags + } } config("profile") { diff --git a/zircon/public/gn/config/standard.gni b/zircon/public/gn/config/standard.gni index 5a7501902ed1be509c78196c87eda04a7a1742ad..66c24f454c35ef83e0054a897474be61c24ef1bd 100644 --- a/zircon/public/gn/config/standard.gni +++ b/zircon/public/gn/config/standard.gni @@ -293,6 +293,16 @@ standard_variants += [ tags = [ "sancov" ] } }, + { + variant = { + name = "ubsan-sancov-full" + bases = [ "ubsan" ] + + # The "sancov" tag is important: see $zx/system/ulib/c/sanitizers. + configs = [ "$zx/public/gn/config/instrumentation:sancov-full" ] + tags = [ "sancov" ] + } + }, ] # This list is appended to the $variants list for the build. It provides diff --git a/zircon/system/ulib/c/sanitizers/sancov-stubs.cpp b/zircon/system/ulib/c/sanitizers/sancov-stubs.cpp index 3caba98517116b3463cc966e4683454b69992beb..26bbda011a4408b26fa8f4f7bc11b91eb0281c7a 100644 --- a/zircon/system/ulib/c/sanitizers/sancov-stubs.cpp +++ b/zircon/system/ulib/c/sanitizers/sancov-stubs.cpp @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "sancov-stubs.h" + // This file defines all the entry points that -fsanitize-coverage=... // instrumentation calls. Unfortunately, LLVM does not publish any header // file declaring those signatures, though they are all given in @@ -33,3 +35,13 @@ __builtin_trap(); } } + +// There are many hooks that are called a lot but can always safely +// just do nothing. + +#define SANCOV_STUB(name) \ + [[gnu::weak]] extern "C" void __sanitizer_cov_##name() {} + +SANCOV_NOOP_STUBS + +#undef SANCOV_STUB diff --git a/zircon/system/ulib/c/sanitizers/sancov-stubs.h b/zircon/system/ulib/c/sanitizers/sancov-stubs.h new file mode 100644 index 0000000000000000000000000000000000000000..146911ce7c8c034813852e37df0e1e16bcabe4f7 --- /dev/null +++ b/zircon/system/ulib/c/sanitizers/sancov-stubs.h @@ -0,0 +1,37 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +// These macros call SANCOV_STUB(NAME) for each __sanitizer_cov_NAME symbol +// that represents a function called by instrumented code. +// +// SANCOV_STUBS covers all the entry points. +// SANCOV_NOOP_STUBS covers only the subset of SANCOV_STUBS where each +// entry point is ordinarily a no-op that might be called harmlessly +// by code during early startup before the proper runtime is in place. + +#define SANCOV_STUBS \ + SANCOV_STUB(trace_pc_guard) \ + SANCOV_STUB(trace_pc_guard_init) \ + SANCOV_NOOP_STUBS + +#define SANCOV_NOOP_STUBS \ + SANCOV_STUB(trace_cmp) \ + SANCOV_STUB(trace_cmp1) \ + SANCOV_STUB(trace_cmp2) \ + SANCOV_STUB(trace_cmp4) \ + SANCOV_STUB(trace_cmp8) \ + SANCOV_STUB(trace_const_cmp1) \ + SANCOV_STUB(trace_const_cmp2) \ + SANCOV_STUB(trace_const_cmp4) \ + SANCOV_STUB(trace_const_cmp8) \ + SANCOV_STUB(trace_switch) \ + SANCOV_STUB(trace_div4) \ + SANCOV_STUB(trace_div8) \ + SANCOV_STUB(trace_gep) \ + SANCOV_STUB(trace_pc) \ + SANCOV_STUB(trace_pc_indir) \ + SANCOV_STUB(8bit_counters_init) \ + SANCOV_STUB(pcs_init) diff --git a/zircon/third_party/ulib/musl/ldso/BUILD.gn b/zircon/third_party/ulib/musl/ldso/BUILD.gn index 493979e284092e90e7c19d2b6793dfcf1f893450..bfb0886079e8e8dfd7e3fe23a3e25c48078010e7 100644 --- a/zircon/third_party/ulib/musl/ldso/BUILD.gn +++ b/zircon/third_party/ulib/musl/ldso/BUILD.gn @@ -4,15 +4,19 @@ source_set("ldso") { deps = [ + ":dlstart", "$zx/system/ulib/ldmsg", "$zx/third_party/ulib/musl:musl_internal", ] sources = [ "$zx/third_party/ulib/musl/arch/${toolchain.cpu}/dl-entry.S", - "dlstart.c", "dynlink-sancov.S", "dynlink.c", ] + + # This is needed by dynlink-sancov.S and dynlink.c for "sancov-stubs.h". + include_dirs = [ "$zx/system/ulib/c/sanitizers" ] + if (toolchain.libprefix != "") { # The libprefix always ends with a / but that's not part of the # "config" string in the loader-service protocol. @@ -21,3 +25,14 @@ source_set("ldso") { defines = [ "DYNLINK_LDSVC_CONFIG=\"$ldsvc_config\"" ] } } + +source_set("dlstart") { + visibility = [ ":*" ] + deps = [ + "$zx/third_party/ulib/musl:musl_internal", + ] + sources = [ + "dlstart.c", + ] + configs += [ "$zx/public/gn/config:no_sanitizers" ] +} diff --git a/zircon/third_party/ulib/musl/ldso/dlstart.c b/zircon/third_party/ulib/musl/ldso/dlstart.c index 0cc62080c6d9373cd0bb89156a8d6d452449f635..23e6f818fff2b944c22e053f1194075798111979 100644 --- a/zircon/third_party/ulib/musl/ldso/dlstart.c +++ b/zircon/third_party/ulib/musl/ldso/dlstart.c @@ -5,20 +5,7 @@ #include <stdatomic.h> #include <stddef.h> -#ifdef __clang__ -// TODO(mcgrathr): Really we want to compile just this file without -// -fsanitize-coverage, but this works around the issue for now. -__asm__(".weakref __sanitizer_cov_trace_pc_guard, _dlstart_sancov_dummy"); -__asm__(".pushsection .text._dlstart_sancov_dummy,\"ax\",%progbits\n" - ".local _dlstart_sancov_dummy\n" - ".type _dlstart_sancov_dummy,%function\n" - "_dlstart_sancov_dummy: ret\n" - ".size _dlstart_sancov_dummy, . - _dlstart_sancov_dummy\n" - ".popsection"); -#endif - -__LOCAL __NO_SAFESTACK NO_ASAN dl_start_return_t _dl_start(void* start_arg, - void* vdso) { +__LOCAL dl_start_return_t _dl_start(void* start_arg, void* vdso) { ElfW(Addr) base = (uintptr_t)__ehdr_start; const ElfW(Rel)* rel = NULL; const ElfW(Rela)* rela = NULL; diff --git a/zircon/third_party/ulib/musl/ldso/dynlink-sancov.S b/zircon/third_party/ulib/musl/ldso/dynlink-sancov.S index 606029d3bc2fd5c9607e64cb9054a9c0fb2314f8..a0d0d976766a68cbfa389231cce9bd1f911a0c4e 100644 --- a/zircon/third_party/ulib/musl/ldso/dynlink-sancov.S +++ b/zircon/third_party/ulib/musl/ldso/dynlink-sancov.S @@ -4,21 +4,27 @@ #include <asm.h> -// See the end of dynlink.c for what this is about. - -.section .text._dynlink_sancov_trace_pc_guard,"ax",%progbits +#include "sancov-stubs.h" -.weak __sanitizer_cov_trace_pc_guard +// See the end of dynlink.c for what this is about. -ENTRY(_dynlink_sancov_trace_pc_guard) +.macro sancov_stub name + .pushsection .text._dynlink_sancov_\name,"ax",%progbits + .weak __sanitizer_cov_\name + ENTRY(_dynlink_sancov_\name) #ifdef __x86_64__ - jmp *__sanitizer_cov_trace_pc_guard@GOTPCREL(%rip) + jmp *__sanitizer_cov_\name@GOTPCREL(%rip) #elif defined(__aarch64__) - adrp x16, :got:__sanitizer_cov_trace_pc_guard - ldr x16, [x16, #:got_lo12:__sanitizer_cov_trace_pc_guard] - br x16 + adrp x16, :got:__sanitizer_cov_\name + ldr x16, [x16, #:got_lo12:__sanitizer_cov_\name] + br x16 #else # error unsupported architecture #endif -END(_dynlink_sancov_trace_pc_guard) -.hidden _dynlink_sancov_trace_pc_guard + END(_dynlink_sancov_\name) + .hidden _dynlink_sancov_\name + .popsection +.endm + +#define SANCOV_STUB(name) sancov_stub name; +SANCOV_STUBS diff --git a/zircon/third_party/ulib/musl/ldso/dynlink.c b/zircon/third_party/ulib/musl/ldso/dynlink.c index bf7248076762aa63200db9bcd158598bc22f9eec..1774fe56b7c214fb695be425df8045220b7b106c 100644 --- a/zircon/third_party/ulib/musl/ldso/dynlink.c +++ b/zircon/third_party/ulib/musl/ldso/dynlink.c @@ -1696,8 +1696,7 @@ __NO_SAFESTACK static void update_tls_size(void) { static dl_start_return_t __dls3(void* start_arg); __NO_SAFESTACK NO_ASAN __attribute__((__visibility__("hidden"))) -dl_start_return_t __dls2( - void* start_arg, void* vdso_map) { +dl_start_return_t __dls2(void* start_arg, void* vdso_map) { ldso.l_map.l_addr = (uintptr_t)__ehdr_start; Ehdr* ehdr = (void*)ldso.l_map.l_addr; @@ -2702,26 +2701,39 @@ zx_status_t __sanitizer_change_code_protection(uintptr_t addr, size_t len, // directly to our definition. The trampoline checks the 'runtime' flag to // distinguish calls before final relocation is complete, and only calls // into the sanitizer runtime once it's actually up. Because of the -// .weakref chicanery, _dynlink_sancov_trace_pc_guard must be in a separate +// .weakref chicanery, the _dynlink_sancov_* symbols must be in a separate // assembly file. -__asm__(".weakref __sanitizer_cov_trace_pc_guard, _dynlink_sancov_trampoline"); -__asm__(".hidden _dynlink_sancov_trace_pc_guard"); -__asm__(".pushsection .text._dynlink_sancov_trampoline,\"ax\",%progbits\n" - ".local _dynlink_sancov_trampoline\n" - ".type _dynlink_sancov_trampoline,%function\n" - "_dynlink_sancov_trampoline:\n" + +# include "sancov-stubs.h" + +# define SANCOV_STUB(name) SANCOV_STUB_ASM(#name) +# define SANCOV_STUB_ASM(name) \ + __asm__( \ + ".weakref __sanitizer_cov_" name ", _dynlink_sancov_trampoline_" name "\n" \ + ".hidden _dynlink_sancov_" name "\n" \ + ".pushsection .text._dynlink_sancov_trampoline_" name ",\"ax\",%progbits\n"\ + ".local _dynlink_sancov_trampoline_" name "\n" \ + ".type _dynlink_sancov_trampoline_" name ",%function\n" \ + "_dynlink_sancov_trampoline_" name ":\n" \ + SANCOV_STUB_ASM_BODY(name) \ + ".size _dynlink_sancov_trampoline_" name ", . - _dynlink_sancov_trampoline_" name "\n" \ + ".popsection"); + # ifdef __x86_64__ - "cmpl $0, _dynlink_runtime(%rip)\n" - "jne _dynlink_sancov_trace_pc_guard\n" +# define SANCOV_STUB_ASM_BODY(name) \ + "cmpl $0, _dynlink_runtime(%rip)\n" \ + "jne _dynlink_sancov_" name "\n" \ "ret\n" # elif defined(__aarch64__) - "adrp x16, _dynlink_runtime\n" - "ldr w16, [x16, #:lo12:_dynlink_runtime]\n" - "cbnz w16, _dynlink_sancov_trace_pc_guard\n" +# define SANCOV_STUB_ASM_BODY(name) \ + "adrp x16, _dynlink_runtime\n" \ + "ldr w16, [x16, #:lo12:_dynlink_runtime]\n" \ + "cbnz w16, _dynlink_sancov_" name "\n" \ "ret\n" # else # error unsupported architecture # endif - ".size _dynlink_sancov_trampoline, . - _dynlink_sancov_trampoline\n" - ".popsection"); + +SANCOV_STUBS + #endif