[RFC,11/X,libsanitizer] Uncolour stack frame on function exit

Message ID VI1PR08MB54714F7177B32B32A439B387E0BA0@VI1PR08MB5471.eurprd08.prod.outlook.com
State New
Headers show
Series
  • [RFC,11/X,libsanitizer] Uncolour stack frame on function exit
Related show

Commit Message

Matthew Malcomson Sept. 6, 2019, 2:46 p.m.
When exiting a function we need to ensure the shadow stack for this
function has no remaining colour.  Without clearing the shadow stack
area for this function pointer checks to later function calls could
check untagged areas (such as parameters passed on the stack) against
a shadow stack area with left-over colour causing a false-positive.

Here we ensure that the entire stack frame is cleared on function exit.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (hwasan_emit_uncolour_frame): New.
	* asan.h (hwasan_emit_uncolour_frame): New.
	* cfgexpand.c (expand_used_vars): Uncolour shadow frame on
	function exit.



###############     Attachment also inlined for ease of reply    ###############
diff --git a/gcc/asan.h b/gcc/asan.h
index 028afdd2e7d16245c6cbbe106b7ccb9c5034d542..c5492ce35980d0b26d4707f96482b69dc76a525a 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -31,6 +31,7 @@ extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
+extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
diff --git a/gcc/asan.c b/gcc/asan.c
index d361b4b562f75cb0c2e081218073eacb3704f8d0..0e74e32ae6ca4e130b3f13abe110364b119def46 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3836,6 +3836,46 @@ hwasan_emit_prologue (rtx *bases,
     }
 }
 
+rtx_insn *
+hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
+{
+  if (before)
+    push_to_sequence (before);
+  else
+    start_sequence ();
+
+  dynamic = convert_memory_address (ptr_mode, dynamic);
+  vars = convert_memory_address (ptr_mode, vars);
+
+  rtx top_rtx;
+  rtx bot_rtx;
+  if (STACK_GROWS_DOWNWARD)
+    {
+      top_rtx = vars;
+      bot_rtx = dynamic;
+    }
+  else
+    {
+      top_rtx = dynamic;
+      bot_rtx = vars;
+    }
+
+  rtx size_rtx = expand_simple_binop (Pmode, MINUS, top_rtx, bot_rtx,
+				  NULL_RTX, /* unsignedp = */0, OPTAB_DIRECT);
+
+  /* TODO Other options (i.e. inline options)  */
+  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+  emit_library_call (ret, LCT_NORMAL, VOIDmode,
+      bot_rtx, ptr_mode,
+      const0_rtx, QImode,
+      size_rtx, ptr_mode);
+
+  do_pending_stack_adjust ();
+  rtx_insn *insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
 rtx
 hwasan_create_untagged_base (rtx orig_base)
 {
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index aacf210facc462675a980ee87bd38d4a7d94ad09..9f0872b32354cbc3186f3f2d2600f711a46926d1 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2412,6 +2412,14 @@ expand_used_vars (void)
     var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
 					      virtual_stack_vars_rtx,
 					      var_end_seq);
+  /* Here we uncolour the entire frame for this function.
+     We need to uncolour *something* if either we have coloured some local
+     variables or we have coloured some alloca objects.  */
+  else if (memory_tagging_p ()
+	   && (cfun->calls_alloca || stack_vars_num > 0))
+    var_end_seq = hwasan_emit_uncolour_frame (virtual_stack_dynamic_rtx,
+					      virtual_stack_vars_rtx,
+					      var_end_seq);
 
   fini_vars_expansion ();

Patch

diff --git a/gcc/asan.h b/gcc/asan.h
index 028afdd2e7d16245c6cbbe106b7ccb9c5034d542..c5492ce35980d0b26d4707f96482b69dc76a525a 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -31,6 +31,7 @@  extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
+extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
diff --git a/gcc/asan.c b/gcc/asan.c
index d361b4b562f75cb0c2e081218073eacb3704f8d0..0e74e32ae6ca4e130b3f13abe110364b119def46 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3836,6 +3836,46 @@  hwasan_emit_prologue (rtx *bases,
     }
 }
 
+rtx_insn *
+hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
+{
+  if (before)
+    push_to_sequence (before);
+  else
+    start_sequence ();
+
+  dynamic = convert_memory_address (ptr_mode, dynamic);
+  vars = convert_memory_address (ptr_mode, vars);
+
+  rtx top_rtx;
+  rtx bot_rtx;
+  if (STACK_GROWS_DOWNWARD)
+    {
+      top_rtx = vars;
+      bot_rtx = dynamic;
+    }
+  else
+    {
+      top_rtx = dynamic;
+      bot_rtx = vars;
+    }
+
+  rtx size_rtx = expand_simple_binop (Pmode, MINUS, top_rtx, bot_rtx,
+				  NULL_RTX, /* unsignedp = */0, OPTAB_DIRECT);
+
+  /* TODO Other options (i.e. inline options)  */
+  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+  emit_library_call (ret, LCT_NORMAL, VOIDmode,
+      bot_rtx, ptr_mode,
+      const0_rtx, QImode,
+      size_rtx, ptr_mode);
+
+  do_pending_stack_adjust ();
+  rtx_insn *insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
 rtx
 hwasan_create_untagged_base (rtx orig_base)
 {
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index aacf210facc462675a980ee87bd38d4a7d94ad09..9f0872b32354cbc3186f3f2d2600f711a46926d1 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2412,6 +2412,14 @@  expand_used_vars (void)
     var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
 					      virtual_stack_vars_rtx,
 					      var_end_seq);
+  /* Here we uncolour the entire frame for this function.
+     We need to uncolour *something* if either we have coloured some local
+     variables or we have coloured some alloca objects.  */
+  else if (memory_tagging_p ()
+	   && (cfun->calls_alloca || stack_vars_num > 0))
+    var_end_seq = hwasan_emit_uncolour_frame (virtual_stack_dynamic_rtx,
+					      virtual_stack_vars_rtx,
+					      var_end_seq);
 
   fini_vars_expansion ();