summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSoby Mathew <soby.mathew@arm.com>2019-09-12 11:14:21 +0000
committerTrustedFirmware Code Review <review@review.trustedfirmware.org>2019-09-12 11:14:21 +0000
commit684b3a02053badb12f6643f7feeae6e0aa394560 (patch)
tree13c16eb11133d47322253a2a0e141774fcff8c32
parentf38e5182f7e60d8c193cbf7712982c0ed7f47cdb (diff)
parent1f4619796af5baf4b41b5723bbf708355f8597fa (diff)
Merge "Add UBSAN support and handlers" into integration
-rw-r--r--Makefile20
-rw-r--r--bl31/aarch64/runtime_exceptions.S57
-rw-r--r--docs/getting_started/user-guide.rst15
-rw-r--r--include/arch/aarch64/arch.h3
-rw-r--r--make_helpers/defaults.mk2
-rw-r--r--plat/common/ubsan.c220
6 files changed, 317 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 43ff8d2f..043e751a 100644
--- a/Makefile
+++ b/Makefile
@@ -278,6 +278,14 @@ TF_CFLAGS += $(CPPFLAGS) $(TF_CFLAGS_$(ARCH)) \
-ffreestanding -fno-builtin -Wall -std=gnu99 \
-Os -ffunction-sections -fdata-sections
+ifeq (${SANITIZE_UB},on)
+TF_CFLAGS += -fsanitize=undefined -fno-sanitize-recover
+endif
+ifeq (${SANITIZE_UB},trap)
+TF_CFLAGS += -fsanitize=undefined -fno-sanitize-recover \
+ -fsanitize-undefined-trap-on-error
+endif
+
GCC_V_OUTPUT := $(shell $(CC) -v 2>&1)
ifneq ($(findstring armlink,$(notdir $(LD))),)
@@ -313,6 +321,10 @@ ifeq ($(notdir $(CC)),armclang)
BL_COMMON_SOURCES += lib/${ARCH}/armclang_printf.S
endif
+ifeq (${SANITIZE_UB},on)
+BL_COMMON_SOURCES += plat/common/ubsan.c
+endif
+
INCLUDES += -Iinclude \
-Iinclude/arch/${ARCH} \
-Iinclude/lib/cpus/${ARCH} \
@@ -673,6 +685,10 @@ $(eval $(call assert_numeric,ARM_ARCH_MAJOR))
$(eval $(call assert_numeric,ARM_ARCH_MINOR))
$(eval $(call assert_numeric,BRANCH_PROTECTION))
+ifeq ($(filter $(SANITIZE_UB), on off trap),)
+ $(error "Invalid value for SANITIZE_UB: can be one of on, off, trap")
+endif
+
################################################################################
# Add definitions to the cpp preprocessor based on the current build options.
# This is done after including the platform specific makefile to allow the
@@ -724,6 +740,10 @@ $(eval $(call add_define,WARMBOOT_ENABLE_DCACHE_EARLY))
$(eval $(call add_define,BL2_AT_EL3))
$(eval $(call add_define,BL2_IN_XIP_MEM))
+ifeq (${SANITIZE_UB},trap)
+ $(eval $(call add_define,MONITOR_TRAPS))
+endif
+
# Define the EL3_PAYLOAD_BASE flag only if it is provided.
ifdef EL3_PAYLOAD_BASE
$(eval $(call add_define,EL3_PAYLOAD_BASE))
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index fd7656e2..1cbec8fd 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -220,6 +220,19 @@ vector_base runtime_exceptions
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_sp_el0
+#ifdef MONITOR_TRAPS
+ stp x29, x30, [sp, #-16]!
+
+ mrs x30, esr_el3
+ ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+ /* Check for BRK */
+ cmp x30, #EC_BRK
+ b.eq brk_handler
+
+ ldp x29, x30, [sp], #16
+#endif /* MONITOR_TRAPS */
+
/* We don't expect any synchronous exceptions from EL3 */
b report_unhandled_exception
end_vector_entry sync_exception_sp_el0
@@ -328,6 +341,14 @@ vector_entry serror_aarch32
b enter_lower_el_async_ea
end_vector_entry serror_aarch32
+#ifdef MONITOR_TRAPS
+ .section .rodata.brk_string, "aS"
+brk_location:
+ .asciz "Error at instruction 0x"
+brk_message:
+ .asciz "Unexpected BRK instruction with value 0x"
+#endif /* MONITOR_TRAPS */
+
/* ---------------------------------------------------------------------
* The following code handles secure monitor calls.
* Depending upon the execution state from where the SMC has been
@@ -455,3 +476,39 @@ rt_svc_fw_critical_error:
msr spsel, #1
no_ret report_unhandled_exception
endfunc smc_handler
+
+ /* ---------------------------------------------------------------------
+ * The following code handles exceptions caused by BRK instructions.
+ * Following a BRK instruction, the only real valid cause of action is
+ * to print some information and panic, as the code that caused it is
+ * likely in an inconsistent internal state.
+ *
+ * This is initially intended to be used in conjunction with
+ * __builtin_trap.
+ * ---------------------------------------------------------------------
+ */
+#ifdef MONITOR_TRAPS
+func brk_handler
+ /* Extract the ISS */
+ mrs x10, esr_el3
+ ubfx x10, x10, #ESR_ISS_SHIFT, #ESR_ISS_LENGTH
+
+ /* Ensure the console is initialized */
+ bl plat_crash_console_init
+
+ adr x4, brk_location
+ bl asm_print_str
+ mrs x4, elr_el3
+ bl asm_print_hex
+ bl asm_print_newline
+
+ adr x4, brk_message
+ bl asm_print_str
+ mov x4, x10
+ mov x5, #28
+ bl asm_print_hex_bits
+ bl asm_print_newline
+
+ no_ret plat_panic_handler
+endfunc brk_handler
+#endif /* MONITOR_TRAPS */
diff --git a/docs/getting_started/user-guide.rst b/docs/getting_started/user-guide.rst
index b447f149..1cfd4c73 100644
--- a/docs/getting_started/user-guide.rst
+++ b/docs/getting_started/user-guide.rst
@@ -684,6 +684,21 @@ Common build options
file that contains the ROT private key in PEM format. If ``SAVE_KEYS=1``, this
file name will be used to save the key.
+- ``SANITIZE_UB``: This option enables the Undefined Behaviour sanitizer. It
+ can take 3 values: 'off' (default), 'on' and 'trap'. When using 'trap',
+ gcc and clang will insert calls to ``__builtin_trap`` on detected
+ undefined behaviour, which defaults to a ``brk`` instruction. When using
+ 'on', undefined behaviour is translated to a call to special handlers which
+ prints the exact location of the problem and its cause and then panics.
+
+ .. note::
+ Because of the space penalty of the Undefined Behaviour sanitizer,
+ this option will increase the size of the binary. Depending on the
+ memory constraints of the target platform, it may not be possible to
+ enable the sanitizer for all images (BL1 and BL2 are especially
+ likely to be memory constrained). We recommend that the
+ sanitizer is enabled only in debug builds.
+
- ``SAVE_KEYS``: This option is used when ``GENERATE_COT=1``. It tells the
certificate generation tool to save the keys used to establish the Chain of
Trust. Allowed options are '0' or '1'. Default is '0' (do not save).
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 5f84eced..0a26fab1 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -598,6 +598,8 @@
#define ESR_EC_SHIFT U(26)
#define ESR_EC_MASK U(0x3f)
#define ESR_EC_LENGTH U(6)
+#define ESR_ISS_SHIFT U(0)
+#define ESR_ISS_LENGTH U(25)
#define EC_UNKNOWN U(0x0)
#define EC_WFE_WFI U(0x1)
#define EC_AARCH32_CP15_MRC_MCR U(0x3)
@@ -624,6 +626,7 @@
#define EC_AARCH32_FP U(0x28)
#define EC_AARCH64_FP U(0x2c)
#define EC_SERROR U(0x2f)
+#define EC_BRK U(0x3c)
/*
* External Abort bit in Instruction and Data Aborts synchronous exception
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index f63e46f3..fa213355 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -224,3 +224,5 @@ ifneq (${ARCH},aarch32)
else
override ENABLE_SVE_FOR_NS := 0
endif
+
+SANITIZE_UB := off
diff --git a/plat/common/ubsan.c b/plat/common/ubsan.c
new file mode 100644
index 00000000..45b0f7cc
--- /dev/null
+++ b/plat/common/ubsan.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+struct source_location {
+ const char *file_name;
+ uint32_t line;
+ uint32_t column;
+};
+
+struct type_descriptor {
+ uint16_t type_kind;
+ uint16_t type_info;
+ char type_name[1];
+};
+
+struct type_mismatch_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+ unsigned long alignment;
+ unsigned char type_check_kind;
+};
+
+struct overflow_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+};
+
+struct shift_out_of_bounds_data {
+ struct source_location loc;
+ struct type_descriptor *lhs_type;
+ struct type_descriptor *rhs_type;
+};
+
+struct out_of_bounds_data {
+ struct source_location loc;
+ struct type_descriptor *array_type;
+ struct type_descriptor *index_type;
+};
+
+struct unreachable_data {
+ struct source_location loc;
+};
+
+struct vla_bound_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+};
+
+struct invalid_value_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+};
+
+struct nonnull_arg_data {
+ struct source_location loc;
+};
+
+/*
+ * When compiling with -fsanitize=undefined the compiler expects functions
+ * with the following signatures. The functions are never called directly,
+ * only when undefined behavior is detected in instrumented code.
+ */
+void __ubsan_handle_type_mismatch_abort(struct type_mismatch_data *data,
+ unsigned long ptr);
+void __ubsan_handle_type_mismatch_v1_abort(struct type_mismatch_data *data,
+ unsigned long ptr);
+void __ubsan_handle_add_overflow_abort(struct overflow_data *data,
+ unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_sub_overflow_abort(struct overflow_data *data,
+ unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_mul_overflow_abort(struct overflow_data *data,
+ unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_negate_overflow_abort(struct overflow_data *data,
+ unsigned long old_val);
+void __ubsan_handle_pointer_overflow_abort(struct overflow_data *data,
+ unsigned long old_val);
+void __ubsan_handle_divrem_overflow_abort(struct overflow_data *data,
+ unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_shift_out_of_bounds_abort(struct shift_out_of_bounds_data *data,
+ unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_out_of_bounds_abort(struct out_of_bounds_data *data,
+ unsigned long idx);
+void __ubsan_handle_unreachable_abort(struct unreachable_data *data);
+void __ubsan_handle_missing_return_abort(struct unreachable_data *data);
+void __ubsan_handle_vla_bound_not_positive_abort(struct vla_bound_data *data,
+ unsigned long bound);
+void __ubsan_handle_load_invalid_value_abort(struct invalid_value_data *data,
+ unsigned long val);
+void __ubsan_handle_nonnull_arg_abort(struct nonnull_arg_data *data
+#if __GCC_VERSION < 60000
+ , size_t arg_no
+#endif
+ );
+
+static void print_loc(const char *func, struct source_location *loc)
+{
+ ERROR("Undefined behavior at %s:%d col %d (%s)",
+ loc->file_name, loc->line, loc->column, func);
+}
+
+
+void __ubsan_handle_type_mismatch_abort(struct type_mismatch_data *data,
+ unsigned long ptr __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_type_mismatch_v1_abort(struct type_mismatch_data *data,
+ unsigned long ptr __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_add_overflow_abort(struct overflow_data *data,
+ unsigned long lhs __unused,
+ unsigned long rhs __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_sub_overflow_abort(struct overflow_data *data,
+ unsigned long lhs __unused,
+ unsigned long rhs __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_mul_overflow_abort(struct overflow_data *data,
+ unsigned long lhs __unused,
+ unsigned long rhs __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_negate_overflow_abort(struct overflow_data *data,
+ unsigned long old_val __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_pointer_overflow_abort(struct overflow_data *data,
+ unsigned long old_val __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_divrem_overflow_abort(struct overflow_data *data,
+ unsigned long lhs __unused,
+ unsigned long rhs __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_shift_out_of_bounds_abort(struct shift_out_of_bounds_data *data,
+ unsigned long lhs __unused,
+ unsigned long rhs __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_out_of_bounds_abort(struct out_of_bounds_data *data,
+ unsigned long idx __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_unreachable_abort(struct unreachable_data *data)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_missing_return_abort(struct unreachable_data *data)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_vla_bound_not_positive_abort(struct vla_bound_data *data,
+ unsigned long bound __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_load_invalid_value_abort(struct invalid_value_data *data,
+ unsigned long val __unused)
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}
+
+void __ubsan_handle_nonnull_arg_abort(struct nonnull_arg_data *data
+#if __GCC_VERSION < 60000
+ , size_t arg_no __unused
+#endif
+ )
+{
+ print_loc(__func__, &data->loc);
+ plat_panic_handler();
+}