| From 41a82fb711f3637b4b7f57756492b628058f9d5f Mon Sep 17 00:00:00 2001 |
| From: Harshit Sharma <harshitsharmajs@gmail.com> |
| Date: Fri, 10 Jul 2020 13:06:08 -0700 |
| Subject: [PATCH] crossgcc: Enable GCC to get asan shadow offset at runtime |
| |
| Unlike Linux kernel which has a static shadow region layout, we have multiple stages in |
| coreboot and thus require a different shadow offset address. Unfortunately, GCC currently |
| only supports adding a static shadow offset at compile time using -fasan-shadow-offset flag. |
| |
| For this reason, we enable GCC to determine asan shadow offset address at runtime using a |
| callback function named __asan_shadow_offset(). This supersedes the need to specify this |
| address at compile time. GCC then makes use of this shadow offset to protect stack buffers |
| by inserting red zones around them. |
| |
| Some other benefits of having this GCC patch are: |
| a. We can place the shadow region in a separate linker section with all its advantages like |
| automatic fit insurance. This ensures if a platform doesn't have enough memory space to |
| hold shadow region, the build will fail. (However, if we use a fixed shadow offset on a |
| platform that actually doesn't have enough memory, it may still build without any errors.) |
| b. We don't modify the memory layout compared to the current one, as we are placing the |
| shadow region at the end of the space already occupied by the program. |
| c. We can be much more flexible later if needed (thinking of other stages like bootblock). |
| d. Since we are appending the shadow buffer to the region already occupied, we make efficient |
| use of the limited memory available which is highly beneficial when using cache as ram. |
| |
| Further, we have made sure that if you compile you tree with ASan enabled but missed this |
| patch, it will end up in the following compilation error: |
| "invalid --param name 'asan-use-shadow-offset-callback'" |
| So, you cannot accidentally enable the feature without having your compiler patched. |
| |
| Signed-off-by: Harshit Sharma <harshitsharmajs@gmail.com> |
| --- |
| gcc/asan.c | 29 ++++++++++++++++++++++------- |
| gcc/params.def | 6 ++++++ |
| gcc/params.h | 2 ++ |
| 3 files changed, 30 insertions(+), 7 deletions(-) |
| |
| diff --git a/gcc/asan.c b/gcc/asan.c |
| index 235e21947..713bf994d 100644 |
| --- a/gcc/asan.c |
| +++ b/gcc/asan.c |
| @@ -1389,13 +1389,28 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb, |
| TREE_ASM_WRITTEN (decl) = 1; |
| TREE_ASM_WRITTEN (id) = 1; |
| emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl))); |
| - shadow_base = expand_binop (Pmode, lshr_optab, base, |
| - gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT), |
| - NULL_RTX, 1, OPTAB_DIRECT); |
| - shadow_base |
| - = plus_constant (Pmode, shadow_base, |
| - asan_shadow_offset () |
| - + (base_align_bias >> ASAN_SHADOW_SHIFT)); |
| + if (ASAN_USE_SHADOW_OFFSET_CALLBACK) { |
| + rtx addr, shadow_offset_rtx; |
| + ret = init_one_libfunc ("__asan_shadow_offset"); |
| + addr= convert_memory_address (ptr_mode, base); |
| + ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, |
| + addr, ptr_mode); |
| + shadow_offset_rtx = convert_memory_address (Pmode, ret); |
| + shadow_base = expand_binop (Pmode, lshr_optab, base, |
| + gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT), |
| + NULL_RTX, 1, OPTAB_DIRECT); |
| + shadow_base = expand_binop (Pmode, add_optab, shadow_base, |
| + shadow_offset_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN); |
| + shadow_base = plus_constant (Pmode, shadow_base, |
| + (base_align_bias >> ASAN_SHADOW_SHIFT)); |
| + } else { |
| + shadow_base = expand_binop (Pmode, lshr_optab, base, |
| + gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT), |
| + NULL_RTX, 1, OPTAB_DIRECT); |
| + shadow_base = plus_constant (Pmode, shadow_base, |
| + asan_shadow_offset () |
| + + (base_align_bias >> ASAN_SHADOW_SHIFT)); |
| + } |
| gcc_assert (asan_shadow_set != -1 |
| && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4); |
| shadow_mem = gen_rtx_MEM (SImode, shadow_base); |
| diff --git a/gcc/params.def b/gcc/params.def |
| index dad47ec2b..bfe6eaa0b 100644 |
| --- a/gcc/params.def |
| +++ b/gcc/params.def |
| @@ -1203,6 +1203,12 @@ DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD, |
| "in function becomes greater or equal to this number.", |
| 7000, 0, INT_MAX) |
| |
| +DEFPARAM (PARAM_ASAN_USE_SHADOW_OFFSET_CALLBACK, |
| + "asan-use-shadow-offset-callback", |
| + "Use shadow offset callback function at runtime instead of " |
| + "fixed value at compile time at the cost of runtime overhead.", |
| + 0, 0, 1) |
| + |
| DEFPARAM (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD, |
| "use-after-scope-direct-emission-threshold", |
| "Use direct poisoning/unpoisoning instructions for variables " |
| diff --git a/gcc/params.h b/gcc/params.h |
| index 98249d2a1..d3bd6be38 100644 |
| --- a/gcc/params.h |
| +++ b/gcc/params.h |
| @@ -246,6 +246,8 @@ extern void init_param_values (int *params); |
| PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN) |
| #define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \ |
| PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD) |
| +#define ASAN_USE_SHADOW_OFFSET_CALLBACK \ |
| + PARAM_VALUE (PARAM_ASAN_USE_SHADOW_OFFSET_CALLBACK) |
| #define ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD \ |
| ((unsigned) PARAM_VALUE (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD)) |
| |
| -- |
| 2.17.1 |