This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PINGv2][PATCH] ASan on unaligned accesses



On 03/04/2015 11:07 AM, Andrew Pinski wrote:
On Wed, Mar 4, 2015 at 12:00 AM, Marat Zakirov <m.zakirov@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.zakirov@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
Fixed.

gcc/ChangeLog:

2015-03-12  Marat Zakirov  <m.zakirov@samsung.com>

	* asan.c (asan_emit_stack_protection): Support for misalign accesses.
	(asan_expand_check_ifn): Likewise.
	* common.opt: New flag -fasan-catch-misaligned.
	* doc/invoke.texi: New flag description.
	* opts.c (finish_options): Add check for new flag.
	(common_handle_option): Switch on flag if SANITIZE_KERNEL_ADDRESS.

gcc/testsuite/ChangeLog:

2015-03-12  Marat Zakirov  <m.zakirov@samsung.com>

	* c-c++-common/asan/misalign-catch.c: New test.


diff --git a/gcc/asan.c b/gcc/asan.c
index 9e4a629..80bf2e8 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;
@@ -1193,11 +1192,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 && flag_asan_catch_misaligned)
+	{
+	  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 +1237,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 +1252,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; flag_asan_catch_misaligned && 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 +1319,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)
@@ -2643,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 && !flag_asan_catch_misaligned)
     {
       tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
 					     shadow_ptr_type);
@@ -2662,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 || flag_asan_catch_misaligned)
 	{
 	  gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
 						   base_addr, 7));
diff --git a/gcc/common.opt b/gcc/common.opt
index b49ac46..a7af95e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1161,6 +1161,12 @@ Common Driver Var(flag_report_bug)
 Collect and dump debug information into temporary file if ICE in C/C++
 compiler occured.
 
+fasan-catch-misaligned
+Common Driver Var(flag_asan_catch_misaligned)
+Catch invalid unaligned memory accesses.
+This option is needed to prevent potential ASan false positives due to 
+unaligned to type size memory accesses in some apllication like Linux kernel.
+
 fdump-passes
 Common Var(flag_dump_passes) Init(0)
 Dump optimization passes
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1534ed9..c85aa38 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6680,6 +6680,12 @@ text / bss / data / heap / stack / dso start locations.
 Collect and dump debug information into temporary file if ICE in C/C++
 compiler occured.
 
+@item -fasan-catch-misaligned
+@opindex fasan-catch-misaligned
+Catch invalid unaligned memory accesses.
+This option is needed to prevent potential ASan false positives due to 
+unaligned to type size memory accesses in some apllication like Linux kernel.
+
 @item -fdump-unnumbered
 @opindex fdump-unnumbered
 When doing debugging dumps, suppress instruction numbers and address output.
diff --git a/gcc/opts.c b/gcc/opts.c
index 39c190d..b238b90 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -925,6 +925,9 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       opts->x_flag_aggressive_loop_optimizations = 0;
       opts->x_flag_strict_overflow = 0;
     }
+  
+  if (flag_asan_catch_misaligned && !opts->x_flag_sanitize)
+    error_at (loc, "-fasan-catch-misaligned is valid only with -fsanitize option");
 }
 
 #define LEFT_COLUMN	27
@@ -1662,6 +1665,7 @@ common_handle_option (struct gcc_options *opts,
 	    maybe_set_param_value (PARAM_ASAN_USE_AFTER_RETURN, 0,
 				   opts->x_param_values,
 				   opts_set->x_param_values);
+            flag_asan_catch_misaligned = true;
 	  }
 
 	break;
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..158efd4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/misalign-catch.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-fasan-catch-misaligned" } */
+/* { 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)" } */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]