On Wed, Mar 4, 2015 at 12:00 AM, Marat Zakirov <m.zaki...@samsung.com> wrote:
> Hi all!
>
> Here is the patch which forces ASan to work on memory access without proper
> alignment. it's useful because some programs like linux kernel often cheat
> with alignment which may cause false negatives. This patch needs additional
> support for proper work on unaligned accesses in global data and heap. It
> will be implemented in libsanitizer by separate patch.
>
>
> --Marat
>
> gcc/ChangeLog:
>
> 2015-02-25  Marat Zakirov  <m.zaki...@samsung.com>
>
>         * asan.c (asan_emit_stack_protection): Support for misalign
> accesses.
>         (asan_expand_check_ifn): Likewise.
>         * params.def: New option asan-catch-misaligned.
>         * params.h: New param ASAN_CATCH_MISALIGNED.

Since this parameter can only be true or false, I think it should be a
normal option.  Also you did not add documentation of the param.

Thanks,
Andrew

>
> gcc/testsuite/ChangeLog:
>
> 2015-02-25  Marat Zakirov  <m.zaki...@samsung.com>
>
>         * c-c++-common/asan/misalign-catch.c: New test.
>
>
> diff --git a/gcc/asan.c b/gcc/asan.c
> index b7c2b11..49d0da4 100644
> --- a/gcc/asan.c
> +++ b/gcc/asan.c
> @@ -1050,7 +1050,6 @@ asan_emit_stack_protection (rtx base, rtx pbase,
> unsigned int alignb,
>    rtx_code_label *lab;
>    rtx_insn *insns;
>    char buf[30];
> -  unsigned char shadow_bytes[4];
>    HOST_WIDE_INT base_offset = offsets[length - 1];
>    HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
>    HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
> @@ -1059,6 +1058,7 @@ asan_emit_stack_protection (rtx base, rtx pbase,
> unsigned int alignb,
>    unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
>    tree str_cst, decl, id;
>    int use_after_return_class = -1;
> +  bool misalign = (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ||
> ASAN_CATCH_MISALIGNED;
>
>    if (shadow_ptr_types[0] == NULL_TREE)
>      asan_init_shadow_ptr_types ();
> @@ -1193,11 +1193,37 @@ asan_emit_stack_protection (rtx base, rtx pbase,
> unsigned int alignb,
>    if (STRICT_ALIGNMENT)
>      set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
>    prev_offset = base_offset;
> +
> +  vec<rtx> shadow_mems;
> +  vec<unsigned char> shadow_bytes;
> +
> +  shadow_mems.create(0);
> +  shadow_bytes.create(0);
> +
>    for (l = length; l; l -= 2)
>      {
>        if (l == 2)
>         cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT;
>        offset = offsets[l - 1];
> +      if (l != length && misalign)
> +       {
> +         HOST_WIDE_INT aoff
> +           = base_offset + ((offset - base_offset)
> +                            & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
> +             - ASAN_RED_ZONE_SIZE;
> +         if (aoff > prev_offset)
> +           {
> +             shadow_mem = adjust_address (shadow_mem, VOIDmode,
> +                                          (aoff - prev_offset)
> +                                          >> ASAN_SHADOW_SHIFT);
> +             prev_offset = aoff;
> +             shadow_bytes.safe_push (0);
> +             shadow_bytes.safe_push (0);
> +             shadow_bytes.safe_push (0);
> +             shadow_bytes.safe_push (0);
> +             shadow_mems.safe_push (shadow_mem);
> +           }
> +       }
>        if ((offset - base_offset) & (ASAN_RED_ZONE_SIZE - 1))
>         {
>           int i;
> @@ -1212,13 +1238,13 @@ asan_emit_stack_protection (rtx base, rtx pbase,
> unsigned int alignb,
>             if (aoff < offset)
>               {
>                 if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1)
> -                 shadow_bytes[i] = 0;
> +                 shadow_bytes.safe_push (0);
>                 else
> -                 shadow_bytes[i] = offset - aoff;
> +                 shadow_bytes.safe_push (offset - aoff);
>               }
>             else
> -             shadow_bytes[i] = ASAN_STACK_MAGIC_PARTIAL;
> -         emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
> +             shadow_bytes.safe_push (ASAN_STACK_MAGIC_PARTIAL);
> +         shadow_mems.safe_push(shadow_mem);
>           offset = aoff;
>         }
>        while (offset <= offsets[l - 2] - ASAN_RED_ZONE_SIZE)
> @@ -1227,12 +1253,21 @@ asan_emit_stack_protection (rtx base, rtx pbase,
> unsigned int alignb,
>                                        (offset - prev_offset)
>                                        >> ASAN_SHADOW_SHIFT);
>           prev_offset = offset;
> -         memset (shadow_bytes, cur_shadow_byte, 4);
> -         emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
> +         shadow_bytes.safe_push (cur_shadow_byte);
> +         shadow_bytes.safe_push (cur_shadow_byte);
> +         shadow_bytes.safe_push (cur_shadow_byte);
> +         shadow_bytes.safe_push (cur_shadow_byte);
> +         shadow_mems.safe_push(shadow_mem);
>           offset += ASAN_RED_ZONE_SIZE;
>         }
>        cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE;
>      }
> +  for (unsigned i = 0; misalign && i < shadow_bytes.length () - 1; i++)
> +    if (shadow_bytes[i] == 0 && shadow_bytes[i + 1] > 0)
> +      shadow_bytes[i] = 8 + (shadow_bytes[i + 1] > 7 ? 0 : shadow_bytes[i +
> 1]);
> +  for (unsigned i = 0; i < shadow_mems.length (); i++)
> +    emit_move_insn (shadow_mems[i], asan_shadow_cst (&shadow_bytes[i *
> 4]));
> +
>    do_pending_stack_adjust ();
>
>    /* Construct epilogue sequence.  */
> @@ -1285,34 +1320,8 @@ asan_emit_stack_protection (rtx base, rtx pbase,
> unsigned int alignb,
>    if (STRICT_ALIGNMENT)
>      set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
>
> -  prev_offset = base_offset;
> -  last_offset = base_offset;
> -  last_size = 0;
> -  for (l = length; l; l -= 2)
> -    {
> -      offset = base_offset + ((offsets[l - 1] - base_offset)
> -                            & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
> -      if (last_offset + last_size != offset)
> -       {
> -         shadow_mem = adjust_address (shadow_mem, VOIDmode,
> -                                      (last_offset - prev_offset)
> -                                      >> ASAN_SHADOW_SHIFT);
> -         prev_offset = last_offset;
> -         asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
> -         last_offset = offset;
> -         last_size = 0;
> -       }
> -      last_size += base_offset + ((offsets[l - 2] - base_offset)
> -                                 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
> -                  - offset;
> -    }
> -  if (last_size)
> -    {
> -      shadow_mem = adjust_address (shadow_mem, VOIDmode,
> -                                  (last_offset - prev_offset)
> -                                  >> ASAN_SHADOW_SHIFT);
> -      asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
> -    }
> +  for (unsigned i = 0; i < shadow_mems.length (); i++)
> +    asan_clear_shadow (shadow_mems[i], 4);
>
>    do_pending_stack_adjust ();
>    if (lab)
> @@ -2544,6 +2553,7 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter,
> bool use_calls)
>    gimple g = gsi_stmt (*iter);
>    location_t loc = gimple_location (g);
>
> +  bool misalign = (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ||
> ASAN_CATCH_MISALIGNED;
>    bool recover_p
>      = (flag_sanitize & flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) !=
> 0;
>
> @@ -2641,7 +2651,7 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter,
> bool use_calls)
>    tree base_addr = gimple_assign_lhs (g);
>
>    tree t = NULL_TREE;
> -  if (real_size_in_bytes >= 8)
> +  if (real_size_in_bytes >= 8 && !misalign)
>      {
>        tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
>                                              shadow_ptr_type);
> @@ -2660,7 +2670,7 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter,
> bool use_calls)
>        /* Aligned (>= 8 bytes) can test just
>          (real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
>          to be 0.  */
> -      if (align < 8)
> +      if (align < 8 || misalign)
>         {
>           gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
>                                                    base_addr, 7));
> diff --git a/gcc/params.def b/gcc/params.def
> index 4d3b398..a22ed22 100644
> --- a/gcc/params.def
> +++ b/gcc/params.def
> @@ -1134,6 +1134,11 @@ DEFPARAM
> (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD,
>           "in function becomes greater or equal to this number",
>           7000, 0, INT_MAX)
>
> +DEFPARAM (PARAM_ASAN_CATCH_MISALIGNED,
> +         "asan-catch-misaligned",
> +         "catch unaligned access",
> +         0, 1, 1)
> +
>  DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS,
>           "uninit-control-dep-attempts",
>           "Maximum number of nested calls to search for control dependencies
> "
> diff --git a/gcc/params.h b/gcc/params.h
> index 2e50ff4..e455327 100644
> --- a/gcc/params.h
> +++ b/gcc/params.h
> @@ -238,5 +238,7 @@ 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_CATCH_MISALIGNED \
> +  PARAM_VALUE (PARAM_ASAN_CATCH_MISALIGNED)
>
>  #endif /* ! GCC_PARAMS_H */
> diff --git a/gcc/testsuite/c-c++-common/asan/misalign-catch.c
> b/gcc/testsuite/c-c++-common/asan/misalign-catch.c
> new file mode 100644
> index 0000000..131cf65
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/asan/misalign-catch.c
> @@ -0,0 +1,21 @@
> +/* { dg-do run } */
> +/* { dg-options "--param asan-catch-misaligned=1" } */
> +/* { dg-shouldfail "asan" } */
> +
> +long long *ptr;
> +
> +__attribute__((noinline))
> +void foo () {
> +   ptr = ((long long int *)(((char *)ptr) + 1));
> +   *ptr = 1;
> +}
> +
> +int main()
> +{
> +   long long int local[9];
> +   ptr = (long long *)&local[8];
> +   foo ();
> +   return 0;
> +}
> +
> +/* { dg-output "ERROR: AddressSanitizer:
> stack-buffer-overflow.*(\n|\r\n|\r)" } */
>

Reply via email to