Introduce -fstack-shuffle, which randomizes local stack variables.
authormartynas <martynas@openbsd.org>
Tue, 6 May 2014 23:22:33 +0000 (23:22 +0000)
committermartynas <martynas@openbsd.org>
Tue, 6 May 2014 23:22:33 +0000 (23:22 +0000)
This will make the environment more hostile and help detect bugs
that depend on overrunning one variable into another, with almost
no performance cost.

Discussed with Theo at m2k14 hackathon.  "oh god yes" tedu@, "oh nice" djm@

gnu/gcc/gcc/cfgexpand.c
gnu/gcc/gcc/common.opt

index ccb534f..88bc17a 100644 (file)
@@ -429,7 +429,21 @@ partition_stack_vars (void)
   if (n == 1)
     return;
 
-  qsort (stack_vars_sorted, n, sizeof (size_t), stack_var_size_cmp);
+  if (flag_stack_shuffle)
+    {
+      /* Fisher-Yates shuffle */
+      for (si = n - 1; si > 0; si--)
+       {
+         size_t tmp;
+         sj = arc4random_uniform(si);
+
+         tmp = stack_vars_sorted[si];
+         stack_vars_sorted[si] = stack_vars_sorted[sj];
+         stack_vars_sorted[sj] = tmp;
+       }
+    }
+  else
+    qsort (stack_vars_sorted, n, sizeof (size_t), stack_var_size_cmp);
 
   /* Special case: detect when all variables conflict, and thus we can't
      do anything during the partitioning loop.  It isn't uncommon (with
@@ -1110,19 +1124,22 @@ expand_used_vars (void)
   /* Assign rtl to each variable based on these partitions.  */
   if (stack_vars_num > 0)
     {
-      /* Reorder decls to be protected by iterating over the variables
-        array multiple times, and allocating out of each phase in turn.  */
-      /* ??? We could probably integrate this into the qsort we did
-        earlier, such that we naturally see these variables first,
-        and thus naturally allocate things in the right order.  */
-      if (has_protected_decls)
+      if (!flag_stack_shuffle)
        {
-         /* Phase 1 contains only character arrays.  */
-         expand_stack_vars (stack_protect_decl_phase_1);
+         /* Reorder decls to be protected by iterating over the variables
+            array multiple times, and allocating out of each phase in turn.  */
+         /* ??? We could probably integrate this into the qsort we did
+            earlier, such that we naturally see these variables first,
+            and thus naturally allocate things in the right order.  */
+         if (has_protected_decls)
+           {
+             /* Phase 1 contains only character arrays.  */
+             expand_stack_vars (stack_protect_decl_phase_1);
 
-         /* Phase 2 contains other kinds of arrays.  */
-         if (flag_stack_protect == 2)
-           expand_stack_vars (stack_protect_decl_phase_2);
+             /* Phase 2 contains other kinds of arrays.  */
+             if (flag_stack_protect == 2)
+               expand_stack_vars (stack_protect_decl_phase_2);
+           }
        }
 
       expand_stack_vars (NULL);
index c309c43..49f05b9 100644 (file)
@@ -874,6 +874,10 @@ fstack-protector-strong
 Common Report RejectNegative Var(flag_stack_protect, 3)
 Use a smart stack protection method for certain functions
 
+fstack-shuffle
+Common Report Var(flag_stack_shuffle)
+Shuffle local stack variables.
+
 fstrength-reduce
 Common
 Does nothing.  Preserved for backward compatibility.