[PATCH] Support asan-fixed-shadow-offset in GCC

2014-07-21 Thread Alexey Preobrazhensky
Hi all,

This patch adds support for non-fixed shadow in asan stack instrumentation.

It is required for Kernel AddressSanitizer, as the shadow offset is
not known at the compile time, and the shadow may not be allocated
during the early boot stages.

This option is intended to be triggered by -fsanitize=kernel-address
option, together with enabling instrumentation with calls.

Bootstrapped®tested on x86_64.

Codereview: https://codereview.appspot.com/118040043/

--
Alexey
2014-07-21  Yury Gribov  
Alexey Preobrazhensky  

New asan-fixed-shadow-offset parameter.

gcc/
* asan.c (asan_emit_stack_protection): Add support for new parameter.
* params.def: Define new parameter.
* params.h: Likewise.

gcc/testsuite/
* c-c++-common/asan/no-fixed-shadow-offset.c: New.

Index: gcc/asan.c
===
--- gcc/asan.c  (revision 212896)
+++ gcc/asan.c  (working copy)
@@ -979,6 +979,8 @@
HOST_WIDE_INT *offsets, tree *decls, int length)
 {
   rtx shadow_base, shadow_mem, ret, mem, orig_base, lab;
+  rtx shadow_start = NULL_RTX;
+  rtx skip_prologue_lab = NULL_RTX, skip_epilogue_lab = NULL_RTX;
   char buf[30];
   unsigned char shadow_bytes[4];
   HOST_WIDE_INT base_offset = offsets[length - 1];
@@ -1112,10 +1114,26 @@
   shadow_base = expand_binop (Pmode, lshr_optab, base,
  GEN_INT (ASAN_SHADOW_SHIFT),
  NULL_RTX, 1, OPTAB_DIRECT);
-  shadow_base
-= plus_constant (Pmode, shadow_base,
-targetm.asan_shadow_offset ()
-+ (base_align_bias >> ASAN_SHADOW_SHIFT));
+  if (ASAN_FIXED_SHADOW_OFFSET)
+{
+  shadow_base
+= plus_constant (Pmode, shadow_base,
+targetm.asan_shadow_offset ()
++ (base_align_bias >> ASAN_SHADOW_SHIFT));
+}
+  else
+{
+  ret = init_one_libfunc ("__asan_get_shadow_ptr");
+  shadow_start = gen_reg_rtx (ptr_mode);
+  emit_library_call_value (ret, shadow_start, LCT_NORMAL, ptr_mode, 0);
+  skip_prologue_lab = gen_label_rtx ();
+  emit_cmp_and_jump_insns (shadow_start, const0_rtx, EQ, NULL_RTX, 
VOIDmode,
+  0, skip_prologue_lab, PROB_VERY_UNLIKELY);
+  shadow_base = expand_binop (Pmode, add_optab, shadow_base, shadow_start,
+ NULL_RTX, 1, OPTAB_DIRECT);
+  shadow_base = plus_constant (Pmode, shadow_base,
+  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);
@@ -1165,17 +1183,19 @@
 }
   do_pending_stack_adjust ();
 
+  if (skip_prologue_lab)
+emit_label (skip_prologue_lab);
+
   /* Construct epilogue sequence.  */
   start_sequence ();
 
-  lab = NULL_RTX;  
   if (use_after_return_class != -1)
 {
-  rtx lab2 = gen_label_rtx ();
   char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
   int very_likely = REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1);
+  lab = gen_label_rtx ();
   emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
-  VOIDmode, 0, lab2, very_likely);
+  VOIDmode, 0, lab, very_likely);
   shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
   set_mem_alias_set (shadow_mem, asan_shadow_set);
   mem = gen_rtx_MEM (ptr_mode, base);
@@ -1204,11 +1224,19 @@
 TYPE_MODE (pointer_sized_int_node),
 orig_addr, ptr_mode);
}
-  lab = gen_label_rtx ();
-  emit_jump (lab);
-  emit_label (lab2);
+  skip_epilogue_lab = gen_label_rtx ();
+  emit_jump (skip_epilogue_lab);
+  emit_label (lab);
 }
 
+  if (!ASAN_FIXED_SHADOW_OFFSET)
+{
+  if (!skip_epilogue_lab)
+   skip_epilogue_lab = gen_label_rtx ();
+  emit_cmp_and_jump_insns (shadow_start, const0_rtx, EQ, NULL_RTX, 
VOIDmode,
+  0, skip_epilogue_lab, PROB_VERY_UNLIKELY);
+}
+
   shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
   set_mem_alias_set (shadow_mem, asan_shadow_set);
 
@@ -1245,9 +1273,10 @@
 }
 
   do_pending_stack_adjust ();
-  if (lab)
-emit_label (lab);
 
+  if (skip_epilogue_lab)
+emit_label (skip_epilogue_lab);
+
   ret = get_insns ();
   end_sequence ();
   return ret;
Index: gcc/params.def
===
--- gcc/params.def  (revision 212896)
+++ gcc/params.def  (working copy)
@@ -1081,6 +1081,11 @@
  " in function becomes greater or equal than this threshold",
  1, 0, INT_MAX)
 
+DEFPARAM (PARAM_ASAN_FIXED_SHADOW_OFFSET,
+ "asan-fixed-shadow-offset",
+

Re: [PATCH] Support asan-fixed-shadow-offset in GCC

2014-07-25 Thread Alexey Preobrazhensky
Our x86_64 implementation it also checks whether frame pointer lies
within direct mapping zone (0x8800-c800), as
some frames are not in that zone and doesn't have shadow.

On Tue, Jul 22, 2014 at 2:43 PM, Andrey Ryabinin  wrote:
> On 07/22/14 14:30, Yury Gribov wrote:
 It is required for Kernel AddressSanitizer, as the shadow offset is
 not known at the compile time,
>>>
>>> To get shadow offset this patch uses function __asan_get_shadow_ptr.
>>> Wouldn't be more effective just to read variable instead of function call?
>>
>> Depends on how much logic you want to hide there. If it's just "return 
>> something" than sure
>> but if you need some synchronization or complex calculations, accessing 
>> global would not be enough.
>>
>
> This function just returns some global variable, and I don't think we will 
> need something more complex in future.
>
>> -Y
>>
>