[build] Support AddressSanitizer userland build with USE_ASAN=true

ASan builds by default go in build-$PROJECT-asan/.
The buildall and run-magenta scripts do ASan builds with the -A switch.

Code that is incompatible with sanitizer builds adds
$(NO_SANITIZERS) to MODULE_COMPILEFLAGS.  Everything else
in userland gets built with ASan.

Using USE_ASAN=true requires a Clang toolchain with the ASan
runtime shared library, which will not land for a while yet.

MG-71 # Enabled all-or-nothing USE_ASAN build switch for Magenta standalone.

Change-Id: Ifc0628934c19affcb909b20f3cfdcc86ee54c2f9
Esse commit está contido em:
Roland McGrath
2017-07-24 15:31:08 -07:00
commit de CQ bot account: commit-bot@chromium.org
commit e379d8860e
11 arquivos alterados com 98 adições e 12 exclusões
+44 -3
Ver Arquivo
@@ -24,7 +24,8 @@ ENABLE_BUILD_LISTFILES := $(call TOBOOL,$(ENABLE_BUILD_LISTFILES))
ENABLE_BUILD_SYSROOT := $(call TOBOOL,$(ENABLE_BUILD_SYSROOT))
ENABLE_NEW_FB := true
ENABLE_ACPI_BUS ?= false
USE_CLANG ?= false
USE_ASAN ?= false
USE_CLANG ?= $(USE_ASAN)
USE_LLD ?= $(USE_CLANG)
ifeq ($(call TOBOOL,$(USE_LLD)),true)
USE_GOLD := false
@@ -39,7 +40,6 @@ LKNAME ?= magenta
CLANG_TARGET_FUCHSIA ?= false
USE_LINKER_GC ?= true
# If no build directory suffix has been explicitly supplied by the environment,
# generate a default based on build options. Start with no suffix, then add
# "-clang" if we are building with clang, and "-release" if we are building with
@@ -47,7 +47,9 @@ USE_LINKER_GC ?= true
ifeq ($(origin BUILDDIR_SUFFIX),undefined)
BUILDDIR_SUFFIX :=
ifeq ($(call TOBOOL,$(USE_CLANG)),true)
ifeq ($(call TOBOOL,$(USE_ASAN)),true)
BUILDDIR_SUFFIX := $(BUILDDIR_SUFFIX)-asan
else ifeq ($(call TOBOOL,$(USE_CLANG)),true)
BUILDDIR_SUFFIX := $(BUILDDIR_SUFFIX)-clang
endif
@@ -187,9 +189,11 @@ endif
ifeq ($(call TOBOOL,$(USE_CLANG)),true)
SAFESTACK := -fsanitize=safe-stack -fstack-protector-strong
NO_SAFESTACK := -fno-sanitize=safe-stack -fno-stack-protector
NO_SANITIZERS := -fno-sanitize=all -fno-stack-protector
else
SAFESTACK :=
NO_SAFESTACK :=
NO_SANITIZERS :=
endif
USER_COMPILEFLAGS += $(SAFESTACK)
@@ -205,6 +209,11 @@ USERLIB_SO_LDFLAGS := $(USER_LDFLAGS) -z defs
# absolute pathname as is used for this on other systems.
USER_SHARED_INTERP := ld.so.1
# Programs built with ASan use the ASan-supporting dynamic linker.
ifeq ($(call TOBOOL,$(USE_ASAN)),true)
USER_SHARED_INTERP := asan/$(USER_SHARED_INTERP)
endif
# Additional flags for building dynamically-linked executables.
USERAPP_LDFLAGS := \
$(USER_LDFLAGS) -pie -dynamic-linker $(USER_SHARED_INTERP)
@@ -381,6 +390,38 @@ ifeq ($(call TOBOOL,$(USE_CLANG)),true)
GLOBAL_COMPILEFLAGS += --target=$(CLANG_ARCH)-fuchsia
endif
ifeq ($(call TOBOOL,$(USE_ASAN)),true)
ifeq ($(call TOBOOL,$(USE_CLANG)),false)
$(error USE_ASAN requires USE_CLANG)
endif
# Compile all of userland with ASan. ASan makes safe-stack superfluous
# and ASan reporting doesn't really grok safe-stack, so disable it.
# Individual modules can append $(NO_SANITIZERS) to counteract this.
USER_COMPILEFLAGS += -fsanitize=address -fno-sanitize=safe-stack
# Ask the Clang driver where the library with SONAME $1 is found at link time.
find-clang-solib = \
$(shell $(CLANG_TOOLCHAIN_PREFIX)clang $(GLOBAL_COMPILEFLAGS) \
-print-file-name=$1)
# Every userland executable and shared library compiled with ASan
# needs to link with $(ASAN_SOLIB). module-user{app,lib}.mk adds it
# to MODULE_EXTRA_OBJS so the linking target will depend on it.
ASAN_SONAME := libclang_rt.asan-$(CLANG_ARCH).so
# TODO(TO-376): It shouldn't need the lib/fuchsia/ prefix here, but it does.
ASAN_SOLIB := $(call find-clang-solib,lib/fuchsia/$(ASAN_SONAME))
USER_MANIFEST_LINES += lib/$(ASAN_SONAME)=$(ASAN_SOLIB)
# The ASan runtime DSO depends on more DSOs from the toolchain. We don't
# link against those, so we don't need any build-time dependencies on them.
# But we need them alongside the ASan runtime DSO in the bootfs.
ASAN_RUNTIME_SONAMES := libc++abi.so.1 libunwind.so.1
USER_MANIFEST_LINES += \
$(foreach soname,$(ASAN_RUNTIME_SONAMES),\
lib/$(soname)=$(call find-clang-solib,$(soname)))
endif
# recursively include any modules in the MODULE variable, leaving a trail of included
# modules in the ALLMODULES list
include make/recurse.mk
+5
Ver Arquivo
@@ -34,6 +34,11 @@ MODULE_SOLIBS := $(foreach lib,$(MODULE_LIBS),$(call TOBUILDDIR,$(lib))/lib$(not
# Include this in every link.
MODULE_EXTRA_OBJS += scripts/dso_handle.ld
# Link the ASan runtime into everything compiled with ASan.
ifeq (,$(filter -fno-sanitize=all,$(MODULE_COMPILEFLAGS)))
MODULE_EXTRA_OBJS += $(ASAN_SOLIB)
endif
$(MODULE_USERAPP_OBJECT): _OBJS := $(USER_CRT1_OBJ) $(MODULE_OBJS) $(MODULE_EXTRA_OBJS)
$(MODULE_USERAPP_OBJECT): _LIBS := $(MODULE_ALIBS) $(MODULE_SOLIBS)
$(MODULE_USERAPP_OBJECT): _LDFLAGS := $(MODULE_LDFLAGS) $(USERAPP_LDFLAGS)
+11 -1
Ver Arquivo
@@ -37,6 +37,11 @@ MODULE_SOLIBS := $(foreach lib,$(MODULE_LIBS),$(call TOBUILDDIR,$(lib))/lib$(not
# Include this in every link.
MODULE_EXTRA_OBJS += scripts/dso_handle.ld
# Link the ASan runtime into everything compiled with ASan.
ifeq (,$(filter -fno-sanitize=all,$(MODULE_COMPILEFLAGS)))
MODULE_EXTRA_OBJS += $(ASAN_SOLIB)
endif
$(MODULE_LIBNAME).so: _OBJS := $(MODULE_OBJS) $(MODULE_EXTRA_OBJS)
$(MODULE_LIBNAME).so: _LIBS := $(MODULE_ALIBS) $(MODULE_SOLIBS)
$(MODULE_LIBNAME).so: _SONAME := lib$(MODULE_SO_NAME).so
@@ -110,7 +115,12 @@ GENERATED += \
endif
ifeq ($(MODULE_SO_INSTALL_NAME),)
MODULE_SO_INSTALL_NAME := lib/lib$(MODULE_SO_NAME).so
MODULE_SO_INSTALL_NAME := lib$(MODULE_SO_NAME).so
# At runtime, ASan-supporting libraries are found in lib/asan/ first.
ifeq ($(call TOBOOL,$(USE_ASAN)),true)
MODULE_SO_INSTALL_NAME := asan/$(MODULE_SO_INSTALL_NAME)
endif
MODULE_SO_INSTALL_NAME := lib/$(MODULE_SO_INSTALL_NAME)
endif
ifneq ($(MODULE_SO_INSTALL_NAME),-)
USER_MANIFEST_LINES += $(MODULE_SO_INSTALL_NAME)=$(MODULE_LIBNAME).so.strip
+16 -1
Ver Arquivo
@@ -14,6 +14,7 @@ function HELP {
echo "-m : Build magenta targets only"
echo "-r : Also build release mode builds"
echo "-c : Also build with clang"
echo "-A : Also build with ASan"
echo "-q : Build quietly"
echo "-h for help"
exit 1
@@ -22,12 +23,14 @@ function HELP {
FAIL_FAST=0
DO_RELEASE=0
DO_CLANG=0
DO_ASAN=0
MAGENTA_ONLY=0
MAKE_ARGS=
QUIET=0
while getopts a:fhmrcq FLAG; do
while getopts Aa:fhmrcq FLAG; do
case $FLAG in
A) DO_ASAN=1;;
a) MAKE_ARGS="${MAKE_ARGS} ${OPTARG}";;
f) FAIL_FAST=1;;
h) HELP;;
@@ -77,6 +80,18 @@ for p in $PROJECTS; do
fi
fi
if [ "$DO_ASAN" -eq 1 ]; then
echo building $p with ASan
nice $DIR/make-parallel $p ${MAKE_ARGS} USE_ASAN=true
STATUS=$?
if [ "$STATUS" -ne 0 ]; then
FAILED="$FAILED $p-asan"
if [ "$FAIL_FAST" -eq 1 ]; then
break
fi
fi
fi
if [ "$DO_RELEASE" -eq 1 ]; then
echo building $p with release
nice $DIR/make-release $p ${MAKE_ARGS}
+8 -2
Ver Arquivo
@@ -12,6 +12,7 @@ function HELP {
echo "-b : build first"
echo "-c <text> : add item to kernel commandline"
echo "-C : use Clang build"
echo "-A : use ASan build"
echo "-d : run with emulated disk"
echo "-D <disk file|device>: specify disk file or device path on host, default is blk.bin"
echo "--disktype[=<type>] : should be one of (ahci, virtio, nvme), default is ahci"
@@ -40,6 +41,7 @@ function HELP {
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ARCH=
ASAN=0
AUDIO=
AUDIO_WAVFILE="/tmp/qemu.wav"
BUILD=0
@@ -68,8 +70,9 @@ else
IFNAME="qemu"
fi
while getopts "a:bc:CdD:gI:km:nNo:q:rs:u:Vx:h-:" FLAG; do
while getopts "Aa:bc:CdD:gI:km:nNo:q:rs:u:Vx:h-:" FLAG; do
case $FLAG in
A) ASAN=1;;
a) ARCH=$OPTARG;;
b) BUILD=1;;
c) CMDLINE+="$OPTARG ";;
@@ -126,7 +129,10 @@ fi
BUILDDIR_SUFFIX=
BUILD_ARGS=
if (( $CLANG )); then
if (( $ASAN )); then
BUILDDIR_SUFFIX+=-asan
BUILD_ARGS=USE_ASAN=true
elif (( $CLANG )); then
BUILDDIR_SUFFIX+=-clang
BUILD_ARGS+=USE_CLANG=true
fi
+1 -1
Ver Arquivo
@@ -38,7 +38,7 @@ MODULE_COMPILEFLAGS += -Ithird_party/ulib/musl/src/internal
MODULE_COMPILEFLAGS += -fvisibility=hidden
# We don't have normal setup, so safe-stack is a non-starter.
MODULE_COMPILEFLAGS += $(NO_SAFESTACK)
MODULE_COMPILEFLAGS += $(NO_SAFESTACK) $(NO_SANITIZERS)
# system/ulib/runtime is compiled without safe-stack. We can't use any other
# static libs, because they might be built with safe-stack or other
+1 -1
Ver Arquivo
@@ -9,7 +9,7 @@ MODULE := $(LOCAL_DIR)
MODULE_TYPE := userlib
# This library should not depend on libc.
MODULE_COMPILEFLAGS := -ffreestanding $(NO_SAFESTACK)
MODULE_COMPILEFLAGS := -ffreestanding $(NO_SAFESTACK) $(NO_SANITIZERS)
MODULE_HEADER_DEPS := kernel/lib/vdso
+5 -1
Ver Arquivo
@@ -59,7 +59,11 @@ static mx_status_t write_ctx_message(
// This function is the entire program that the child process will execute. It
// gets directly mapped into the child process via mx_vmo_write() so it must not
// reference any addressable entity outside it.
__NO_SAFESTACK static void minipr_thread_loop(mx_handle_t channel, uintptr_t fnptr) {
__NO_SAFESTACK
#ifdef __clang__
__attribute__((no_sanitize("all")))
#endif
static void minipr_thread_loop(mx_handle_t channel, uintptr_t fnptr) {
if (fnptr == 0) {
// In this mode we don't have a VDSO so we don't care what the handle is
// and therefore we busy-loop. Unless external steps are taken this will
+1 -1
Ver Arquivo
@@ -22,6 +22,6 @@ MODULE_HEADER_DEPS += \
system/ulib/c
# This code is used in early startup, where safe-stack setup is not ready yet.
MODULE_COMPILEFLAGS += $(NO_SAFESTACK)
MODULE_COMPILEFLAGS += $(NO_SAFESTACK) $(NO_SANITIZERS)
include make/module.mk
+1 -1
Ver Arquivo
@@ -11,7 +11,7 @@ MODULE_TYPE := userlib
# This whole module is a hack to deal with these functions needing to be compiled with
# -fno-stack-protector
MODULE_SRCS += $(LOCAL_DIR)/threads.c
MODULE_COMPILEFLAGS += $(NO_SAFESTACK)
MODULE_COMPILEFLAGS += $(NO_SAFESTACK) $(NO_SANITIZERS)
MODULE_NAME := threads-test-threads
@@ -102,7 +102,12 @@ bool thread_injection_test(void) {
}
BEGIN_TEST_CASE(thread_injection_tests)
// This test is incompatible with ASan, because both the original
// dynamic linker and the injected one would try to set up shadow
// memory in the same place.
#if !__has_feature(address_sanitizer)
RUN_TEST(thread_injection_test)
#endif
END_TEST_CASE(thread_injection_tests)
int main(int argc, char** argv) {