769 lines
29 KiB
Diff
769 lines
29 KiB
Diff
diff -N -urp a/gcc/combine-stack-adj.c b/gcc/combine-stack-adj.c
|
||
--- a/gcc/combine-stack-adj.c 2017-01-20 08:05:30.925466000 +0800
|
||
+++ b/gcc/combine-stack-adj.c 2019-01-10 17:10:16.606528459 +0800
|
||
@@ -508,6 +508,8 @@ combine_stack_adjustments_for_block (bas
|
||
continue;
|
||
|
||
set = single_set_for_csa (insn);
|
||
+ if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
|
||
+ set = NULL_RTX;
|
||
if (set)
|
||
{
|
||
rtx dest = SET_DEST (set);
|
||
diff -N -urp a/gcc/common.opt b/gcc/common.opt
|
||
--- a/gcc/common.opt 2019-01-10 13:33:20.926185828 +0800
|
||
+++ b/gcc/common.opt 2019-01-10 16:37:35.238476827 +0800
|
||
@@ -2336,13 +2336,18 @@ Common Report Var(flag_variable_expansio
|
||
Apply variable expansion when loops are unrolled.
|
||
|
||
fstack-check=
|
||
-Common Report RejectNegative Joined
|
||
+Common Report RejectNegative Joined Optimization
|
||
-fstack-check=[no|generic|specific] Insert stack checking code into the program.
|
||
|
||
fstack-check
|
||
Common Alias(fstack-check=, specific, no)
|
||
Insert stack checking code into the program. Same as -fstack-check=specific.
|
||
|
||
+fstack-clash-protection
|
||
+Common Report Var(flag_stack_clash_protection) Optimization
|
||
+Insert code to probe each page of stack space as it is allocated to protect
|
||
+from stack-clash style attacks.
|
||
+
|
||
fstack-limit
|
||
Common Var(common_deferred_options) Defer
|
||
|
||
diff -N -urp a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
|
||
--- a/gcc/config/aarch64/aarch64.c 2019-01-10 13:33:20.914185828 +0800
|
||
+++ b/gcc/config/aarch64/aarch64.c 2019-01-11 14:12:22.248521895 +0800
|
||
@@ -3881,12 +3881,14 @@ aarch64_expand_prologue (void)
|
||
{
|
||
if (crtl->is_leaf && !cfun->calls_alloca)
|
||
{
|
||
- if (frame_size > PROBE_INTERVAL && frame_size > STACK_CHECK_PROTECT)
|
||
- aarch64_emit_probe_stack_range (STACK_CHECK_PROTECT,
|
||
- frame_size - STACK_CHECK_PROTECT);
|
||
+ if (frame_size > PROBE_INTERVAL
|
||
+ && frame_size > get_stack_check_protect ())
|
||
+ aarch64_emit_probe_stack_range (get_stack_check_protect (),
|
||
+ (frame_size
|
||
+ - get_stack_check_protect ()));
|
||
}
|
||
else if (frame_size > 0)
|
||
- aarch64_emit_probe_stack_range (STACK_CHECK_PROTECT, frame_size);
|
||
+ aarch64_emit_probe_stack_range (get_stack_check_protect (), frame_size);
|
||
}
|
||
|
||
aarch64_sub_sp (IP0_REGNUM, initial_adjust, true);
|
||
diff -N -urp a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
|
||
--- a/gcc/config/i386/i386.c 2019-01-10 13:33:20.674185822 +0800
|
||
+++ b/gcc/config/i386/i386.c 2019-01-28 10:55:37.006876481 +0800
|
||
@@ -14396,7 +14396,7 @@ ix86_expand_prologue (void)
|
||
HOST_WIDE_INT size = allocate;
|
||
|
||
if (TARGET_64BIT && size >= HOST_WIDE_INT_C (0x80000000))
|
||
- size = 0x80000000 - STACK_CHECK_PROTECT - 1;
|
||
+ size = 0x80000000 - get_stack_check_protect () - 1;
|
||
|
||
if (TARGET_STACK_PROBE)
|
||
{
|
||
@@ -14406,18 +14406,21 @@ ix86_expand_prologue (void)
|
||
ix86_emit_probe_stack_range (0, size);
|
||
}
|
||
else
|
||
- ix86_emit_probe_stack_range (0, size + STACK_CHECK_PROTECT);
|
||
+ ix86_emit_probe_stack_range (0,
|
||
+ size + get_stack_check_protect ());
|
||
}
|
||
else
|
||
{
|
||
if (crtl->is_leaf && !cfun->calls_alloca)
|
||
{
|
||
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
|
||
- ix86_emit_probe_stack_range (STACK_CHECK_PROTECT,
|
||
- size - STACK_CHECK_PROTECT);
|
||
+ if (size > PROBE_INTERVAL
|
||
+ && size > get_stack_check_protect ())
|
||
+ ix86_emit_probe_stack_range (get_stack_check_protect (),
|
||
+ (size
|
||
+ - get_stack_check_protect ()));
|
||
}
|
||
else
|
||
- ix86_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
|
||
+ ix86_emit_probe_stack_range (get_stack_check_protect (), size);
|
||
}
|
||
}
|
||
}
|
||
diff -N -urp a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
|
||
--- a/gcc/config/ia64/ia64.c 2017-01-01 20:07:43.905435000 +0800
|
||
+++ b/gcc/config/ia64/ia64.c 2019-01-28 10:58:37.582881234 +0800
|
||
@@ -3481,15 +3481,16 @@ ia64_expand_prologue (void)
|
||
|
||
if (crtl->is_leaf && !cfun->calls_alloca)
|
||
{
|
||
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
|
||
- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT,
|
||
- size - STACK_CHECK_PROTECT,
|
||
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
|
||
+ ia64_emit_probe_stack_range (get_stack_check_protect (),
|
||
+ size - get_stack_check_protect (),
|
||
bs_size);
|
||
- else if (size + bs_size > STACK_CHECK_PROTECT)
|
||
- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, 0, bs_size);
|
||
+ else if (size + bs_size > get_stack_check_protect ())
|
||
+ ia64_emit_probe_stack_range (get_stack_check_protect (),
|
||
+ 0, bs_size);
|
||
}
|
||
else if (size + bs_size > 0)
|
||
- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, size, bs_size);
|
||
+ ia64_emit_probe_stack_range (get_stack_check_protect (), size, bs_size);
|
||
}
|
||
|
||
if (dump_file)
|
||
diff -N -urp a/gcc/coretypes.h b/gcc/coretypes.h
|
||
--- a/gcc/coretypes.h 2017-01-01 20:07:43.905435000 +0800
|
||
+++ b/gcc/coretypes.h 2019-01-11 14:09:58.612518114 +0800
|
||
@@ -371,6 +371,7 @@ typedef unsigned char uchar;
|
||
#include "input.h"
|
||
#include "is-a.h"
|
||
#include "memory-block.h"
|
||
+#include "dumpfile.h"
|
||
#endif /* GENERATOR_FILE && !USED_FOR_TARGET */
|
||
|
||
#endif /* coretypes.h */
|
||
diff -N -urp a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
|
||
--- a/gcc/doc/invoke.texi 2019-01-10 13:33:20.882185827 +0800
|
||
+++ b/gcc/doc/invoke.texi 2019-01-10 16:40:40.066481692 +0800
|
||
@@ -10050,6 +10050,21 @@ compilation without. The value for comp
|
||
needs to be more conservative (higher) in order to make tracer
|
||
effective.
|
||
|
||
+@item stack-clash-protection-guard-size
|
||
+Specify the size of the operating system provided stack guard as
|
||
+2 raised to @var{num} bytes. The default value is 12 (4096 bytes).
|
||
+Acceptable values are between 12 and 30. Higher values may reduce the
|
||
+number of explicit probes, but a value larger than the operating system
|
||
+provided guard will leave code vulnerable to stack clash style attacks.
|
||
+
|
||
+@item stack-clash-protection-probe-interval
|
||
+Stack clash protection involves probing stack space as it is allocated. This
|
||
+param controls the maximum distance between probes into the stack as 2 raised
|
||
+to @var{num} bytes. Acceptable values are between 10 and 16 and defaults to
|
||
+12. Higher values may reduce the number of explicit probes, but a value
|
||
+larger than the operating system provided guard will leave code vulnerable to
|
||
+stack clash style attacks.
|
||
+
|
||
@item max-cse-path-length
|
||
|
||
The maximum number of basic blocks on path that CSE considers.
|
||
@@ -11248,7 +11263,8 @@ target support in the compiler but comes
|
||
@enumerate
|
||
@item
|
||
Modified allocation strategy for large objects: they are always
|
||
-allocated dynamically if their size exceeds a fixed threshold.
|
||
+allocated dynamically if their size exceeds a fixed threshold. Note this
|
||
+may change the semantics of some code.
|
||
|
||
@item
|
||
Fixed limit on the size of the static frame of functions: when it is
|
||
@@ -11263,6 +11279,25 @@ generic implementation, code performance
|
||
Note that old-style stack checking is also the fallback method for
|
||
@samp{specific} if no target support has been added in the compiler.
|
||
|
||
+@samp{-fstack-check=} is designed for Ada's needs to detect infinite recursion
|
||
+and stack overflows. @samp{specific} is an excellent choice when compiling
|
||
+Ada code. It is not generally sufficient to protect against stack-clash
|
||
+attacks. To protect against those you want @samp{-fstack-clash-protection}.
|
||
+
|
||
+@item -fstack-clash-protection
|
||
+@opindex fstack-clash-protection
|
||
+Generate code to prevent stack clash style attacks. When this option is
|
||
+enabled, the compiler will only allocate one page of stack space at a time
|
||
+and each page is accessed immediately after allocation. Thus, it prevents
|
||
+allocations from jumping over any stack guard page provided by the
|
||
+operating system.
|
||
+
|
||
+Most targets do not fully support stack clash protection. However, on
|
||
+those targets @option{-fstack-clash-protection} will protect dynamic stack
|
||
+allocations. @option{-fstack-clash-protection} may also provide limited
|
||
+protection for static stack allocations if the target supports
|
||
+@option{-fstack-check=specific}.
|
||
+
|
||
@item -fstack-limit-register=@var{reg}
|
||
@itemx -fstack-limit-symbol=@var{sym}
|
||
@itemx -fno-stack-limit
|
||
diff -N -urp a/gcc/doc/tm.texi b/gcc/doc/tm.texi
|
||
--- a/gcc/doc/tm.texi 2017-04-05 01:52:27.193766000 +0800
|
||
+++ b/gcc/doc/tm.texi 2019-01-10 16:50:44.006497591 +0800
|
||
@@ -3419,6 +3419,10 @@ GCC computed the default from the values
|
||
normally not need to override that default.
|
||
@end defmac
|
||
|
||
+@deftypefn {Target Hook} bool TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE (rtx @var{residual})
|
||
+Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero.
|
||
+@end deftypefn
|
||
+
|
||
@need 2000
|
||
@node Frame Registers
|
||
@subsection Registers That Address the Stack Frame
|
||
diff -N -urp a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
|
||
--- a/gcc/doc/tm.texi.in 2017-04-05 01:52:27.193766000 +0800
|
||
+++ b/gcc/doc/tm.texi.in 2019-01-10 16:51:41.530499105 +0800
|
||
@@ -2999,6 +2999,8 @@ GCC computed the default from the values
|
||
normally not need to override that default.
|
||
@end defmac
|
||
|
||
+@hook TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE
|
||
+
|
||
@need 2000
|
||
@node Frame Registers
|
||
@subsection Registers That Address the Stack Frame
|
||
diff -N -urp a/gcc/explow.c b/gcc/explow.c
|
||
--- a/gcc/explow.c 2017-02-02 20:39:09.589196000 +0800
|
||
+++ b/gcc/explow.c 2019-01-10 16:56:07.454506105 +0800
|
||
@@ -39,8 +39,10 @@ along with GCC; see the file COPYING3.
|
||
#include "expr.h"
|
||
#include "common/common-target.h"
|
||
#include "output.h"
|
||
+#include "params.h"
|
||
|
||
static rtx break_out_memory_refs (rtx);
|
||
+static void anti_adjust_stack_and_probe_stack_clash (rtx);
|
||
|
||
|
||
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
|
||
@@ -1271,6 +1273,29 @@ get_dynamic_stack_size (rtx *psize, unsi
|
||
*psize = size;
|
||
}
|
||
|
||
+/* Return the number of bytes to "protect" on the stack for -fstack-check.
|
||
+
|
||
+ "protect" in the context of -fstack-check means how many bytes we
|
||
+ should always ensure are available on the stack. More importantly
|
||
+ this is how many bytes are skipped when probing the stack.
|
||
+
|
||
+ On some targets we want to reuse the -fstack-check prologue support
|
||
+ to give a degree of protection against stack clashing style attacks.
|
||
+
|
||
+ In that scenario we do not want to skip bytes before probing as that
|
||
+ would render the stack clash protections useless.
|
||
+
|
||
+ So we never use STACK_CHECK_PROTECT directly. Instead we indirect though
|
||
+ this helper which allows us to provide different values for
|
||
+ -fstack-check and -fstack-clash-protection. */
|
||
+HOST_WIDE_INT
|
||
+get_stack_check_protect (void)
|
||
+{
|
||
+ if (flag_stack_clash_protection)
|
||
+ return 0;
|
||
+ return STACK_CHECK_PROTECT;
|
||
+}
|
||
+
|
||
/* Return an rtx representing the address of an area of memory dynamically
|
||
pushed on the stack.
|
||
|
||
@@ -1429,7 +1454,7 @@ allocate_dynamic_stack_space (rtx size,
|
||
probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
|
||
size);
|
||
else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
|
||
- probe_stack_range (STACK_CHECK_PROTECT, size);
|
||
+ probe_stack_range (get_stack_check_protect (), size);
|
||
|
||
/* Don't let anti_adjust_stack emit notes. */
|
||
suppress_reg_args_size = true;
|
||
@@ -1482,6 +1507,8 @@ allocate_dynamic_stack_space (rtx size,
|
||
|
||
if (flag_stack_check && STACK_CHECK_MOVING_SP)
|
||
anti_adjust_stack_and_probe (size, false);
|
||
+ else if (flag_stack_clash_protection)
|
||
+ anti_adjust_stack_and_probe_stack_clash (size);
|
||
else
|
||
anti_adjust_stack (size);
|
||
|
||
@@ -1757,6 +1784,237 @@ probe_stack_range (HOST_WIDE_INT first,
|
||
emit_insn (gen_blockage ());
|
||
}
|
||
|
||
+/* Compute parameters for stack clash probing a dynamic stack
|
||
+ allocation of SIZE bytes.
|
||
+
|
||
+ We compute ROUNDED_SIZE, LAST_ADDR, RESIDUAL and PROBE_INTERVAL.
|
||
+
|
||
+ Additionally we conditionally dump the type of probing that will
|
||
+ be needed given the values computed. */
|
||
+
|
||
+void
|
||
+compute_stack_clash_protection_loop_data (rtx *rounded_size, rtx *last_addr,
|
||
+ rtx *residual,
|
||
+ HOST_WIDE_INT *probe_interval,
|
||
+ rtx size)
|
||
+{
|
||
+ /* Round SIZE down to STACK_CLASH_PROTECTION_PROBE_INTERVAL. */
|
||
+ *probe_interval
|
||
+ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
|
||
+ *rounded_size = simplify_gen_binary (AND, Pmode, size,
|
||
+ GEN_INT (-*probe_interval));
|
||
+
|
||
+ /* Compute the value of the stack pointer for the last iteration.
|
||
+ It's just SP + ROUNDED_SIZE. */
|
||
+ rtx rounded_size_op = force_operand (*rounded_size, NULL_RTX);
|
||
+ *last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
|
||
+ stack_pointer_rtx,
|
||
+ rounded_size_op),
|
||
+ NULL_RTX);
|
||
+
|
||
+ /* Compute any residuals not allocated by the loop above. Residuals
|
||
+ are just the ROUNDED_SIZE - SIZE. */
|
||
+ *residual = simplify_gen_binary (MINUS, Pmode, size, *rounded_size);
|
||
+
|
||
+ /* Dump key information to make writing tests easy. */
|
||
+ if (dump_file)
|
||
+ {
|
||
+ if (*rounded_size == CONST0_RTX (Pmode))
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash skipped dynamic allocation and probing loop.\n");
|
||
+ else if (CONST_INT_P (*rounded_size)
|
||
+ && INTVAL (*rounded_size) <= 4 * *probe_interval)
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash dynamic allocation and probing inline.\n");
|
||
+ else if (CONST_INT_P (*rounded_size))
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash dynamic allocation and probing in "
|
||
+ "rotated loop.\n");
|
||
+ else
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash dynamic allocation and probing in loop.\n");
|
||
+
|
||
+ if (*residual != CONST0_RTX (Pmode))
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash dynamic allocation and probing residuals.\n");
|
||
+ else
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash skipped dynamic allocation and "
|
||
+ "probing residuals.\n");
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Emit the start of an allocate/probe loop for stack
|
||
+ clash protection.
|
||
+
|
||
+ LOOP_LAB and END_LAB are returned for use when we emit the
|
||
+ end of the loop.
|
||
+
|
||
+ LAST addr is the value for SP which stops the loop. */
|
||
+void
|
||
+emit_stack_clash_protection_probe_loop_start (rtx *loop_lab,
|
||
+ rtx *end_lab,
|
||
+ rtx last_addr,
|
||
+ bool rotated)
|
||
+{
|
||
+ /* Essentially we want to emit any setup code, the top of loop
|
||
+ label and the comparison at the top of the loop. */
|
||
+ *loop_lab = gen_label_rtx ();
|
||
+ *end_lab = gen_label_rtx ();
|
||
+
|
||
+ emit_label (*loop_lab);
|
||
+ if (!rotated)
|
||
+ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX,
|
||
+ Pmode, 1, *end_lab);
|
||
+}
|
||
+
|
||
+/* Emit the end of a stack clash probing loop.
|
||
+
|
||
+ This consists of just the jump back to LOOP_LAB and
|
||
+ emitting END_LOOP after the loop. */
|
||
+
|
||
+void
|
||
+emit_stack_clash_protection_probe_loop_end (rtx loop_lab, rtx end_loop,
|
||
+ rtx last_addr, bool rotated)
|
||
+{
|
||
+ if (rotated)
|
||
+ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, NE, NULL_RTX,
|
||
+ Pmode, 1, loop_lab);
|
||
+ else
|
||
+ emit_jump (loop_lab);
|
||
+
|
||
+ emit_label (end_loop);
|
||
+
|
||
+}
|
||
+
|
||
+/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
|
||
+ while probing it. This pushes when SIZE is positive. SIZE need not
|
||
+ be constant.
|
||
+
|
||
+ This is subtly different than anti_adjust_stack_and_probe to try and
|
||
+ prevent stack-clash attacks
|
||
+
|
||
+ 1. It must assume no knowledge of the probing state, any allocation
|
||
+ must probe.
|
||
+
|
||
+ Consider the case of a 1 byte alloca in a loop. If the sum of the
|
||
+ allocations is large, then this could be used to jump the guard if
|
||
+ probes were not emitted.
|
||
+
|
||
+ 2. It never skips probes, whereas anti_adjust_stack_and_probe will
|
||
+ skip probes on the first couple PROBE_INTERVALs on the assumption
|
||
+ they're done elsewhere.
|
||
+
|
||
+ 3. It only allocates and probes SIZE bytes, it does not need to
|
||
+ allocate/probe beyond that because this probing style does not
|
||
+ guarantee signal handling capability if the guard is hit. */
|
||
+
|
||
+static void
|
||
+anti_adjust_stack_and_probe_stack_clash (rtx size)
|
||
+{
|
||
+ /* First ensure SIZE is Pmode. */
|
||
+ if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
|
||
+ size = convert_to_mode (Pmode, size, 1);
|
||
+
|
||
+ /* We can get here with a constant size on some targets. */
|
||
+ rtx rounded_size, last_addr, residual;
|
||
+ HOST_WIDE_INT probe_interval;
|
||
+ compute_stack_clash_protection_loop_data (&rounded_size, &last_addr,
|
||
+ &residual, &probe_interval, size);
|
||
+
|
||
+ if (rounded_size != CONST0_RTX (Pmode))
|
||
+ {
|
||
+ if (CONST_INT_P (rounded_size)
|
||
+ && INTVAL (rounded_size) <= 4 * probe_interval)
|
||
+ {
|
||
+ for (HOST_WIDE_INT i = 0;
|
||
+ i < INTVAL (rounded_size);
|
||
+ i += probe_interval)
|
||
+ {
|
||
+ anti_adjust_stack (GEN_INT (probe_interval));
|
||
+
|
||
+ /* The prologue does not probe residuals. Thus the offset
|
||
+ here to probe just beyond what the prologue had already
|
||
+ allocated. */
|
||
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
|
||
+ (probe_interval
|
||
+ - GET_MODE_SIZE (word_mode))));
|
||
+ emit_insn (gen_blockage ());
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ rtx loop_lab, end_loop;
|
||
+ bool rotate_loop = CONST_INT_P (rounded_size);
|
||
+ emit_stack_clash_protection_probe_loop_start (&loop_lab, &end_loop,
|
||
+ last_addr, rotate_loop);
|
||
+
|
||
+ anti_adjust_stack (GEN_INT (probe_interval));
|
||
+
|
||
+ /* The prologue does not probe residuals. Thus the offset here
|
||
+ to probe just beyond what the prologue had already allocated. */
|
||
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
|
||
+ (probe_interval
|
||
+ - GET_MODE_SIZE (word_mode))));
|
||
+
|
||
+ emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop,
|
||
+ last_addr, rotate_loop);
|
||
+ emit_insn (gen_blockage ());
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (residual != CONST0_RTX (Pmode))
|
||
+ {
|
||
+ rtx label = NULL_RTX;
|
||
+ /* RESIDUAL could be zero at runtime and in that case *sp could
|
||
+ hold live data. Furthermore, we do not want to probe into the
|
||
+ red zone.
|
||
+
|
||
+ Go ahead and just guard the probe at *sp on RESIDUAL != 0 at
|
||
+ runtime if RESIDUAL is not a compile time constant. */
|
||
+ if (!CONST_INT_P (residual))
|
||
+ {
|
||
+ label = gen_label_rtx ();
|
||
+ emit_cmp_and_jump_insns (residual, CONST0_RTX (GET_MODE (residual)),
|
||
+ EQ, NULL_RTX, Pmode, 1, label);
|
||
+ }
|
||
+
|
||
+ rtx x = force_reg (Pmode, plus_constant (Pmode, residual,
|
||
+ -GET_MODE_SIZE (word_mode)));
|
||
+ anti_adjust_stack (residual);
|
||
+ emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x));
|
||
+ emit_insn (gen_blockage ());
|
||
+ if (!CONST_INT_P (residual))
|
||
+ emit_label (label);
|
||
+ }
|
||
+
|
||
+ /* Some targets make optimistic assumptions in their prologues about
|
||
+ how the caller may have probed the stack. Make sure we honor
|
||
+ those assumptions when needed. */
|
||
+ if (size != CONST0_RTX (Pmode)
|
||
+ && targetm.stack_clash_protection_final_dynamic_probe (residual))
|
||
+ {
|
||
+ /* SIZE could be zero at runtime and in that case *sp could hold
|
||
+ live data. Furthermore, we don't want to probe into the red
|
||
+ zone.
|
||
+
|
||
+ Go ahead and just guard the probe at *sp on SIZE != 0 at runtime
|
||
+ if SIZE is not a compile time constant. */
|
||
+ rtx label = NULL_RTX;
|
||
+ if (!CONST_INT_P (size))
|
||
+ {
|
||
+ label = gen_label_rtx ();
|
||
+ emit_cmp_and_jump_insns (size, CONST0_RTX (GET_MODE (size)),
|
||
+ EQ, NULL_RTX, Pmode, 1, label);
|
||
+ }
|
||
+
|
||
+ emit_stack_probe (stack_pointer_rtx);
|
||
+ emit_insn (gen_blockage ());
|
||
+ if (!CONST_INT_P (size))
|
||
+ emit_label (label);
|
||
+ }
|
||
+}
|
||
+
|
||
/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
|
||
while probing it. This pushes when SIZE is positive. SIZE need not
|
||
be constant. If ADJUST_BACK is true, adjust back the stack pointer
|
||
diff -N -urp a/gcc/explow.h b/gcc/explow.h
|
||
--- a/gcc/explow.h 2017-01-01 20:07:43.905435000 +0800
|
||
+++ b/gcc/explow.h 2019-01-10 16:57:37.934508487 +0800
|
||
@@ -69,6 +69,15 @@ extern void anti_adjust_stack (rtx);
|
||
/* Add some bytes to the stack while probing it. An rtx says how many. */
|
||
extern void anti_adjust_stack_and_probe (rtx, bool);
|
||
|
||
+/* Support for building allocation/probing loops for stack-clash
|
||
+ protection of dyamically allocated stack space. */
|
||
+extern void compute_stack_clash_protection_loop_data (rtx *, rtx *, rtx *,
|
||
+ HOST_WIDE_INT *, rtx);
|
||
+extern void emit_stack_clash_protection_probe_loop_start (rtx *, rtx *,
|
||
+ rtx, bool);
|
||
+extern void emit_stack_clash_protection_probe_loop_end (rtx, rtx,
|
||
+ rtx, bool);
|
||
+
|
||
/* This enum is used for the following two functions. */
|
||
enum save_level {SAVE_BLOCK, SAVE_FUNCTION, SAVE_NONLOCAL};
|
||
|
||
diff -N -urp a/gcc/flag-types.h b/gcc/flag-types.h
|
||
--- a/gcc/flag-types.h 2017-01-01 20:07:43.905435000 +0800
|
||
+++ b/gcc/flag-types.h 2019-01-10 16:42:11.490484099 +0800
|
||
@@ -166,7 +166,14 @@ enum permitted_flt_eval_methods
|
||
PERMITTED_FLT_EVAL_METHODS_C11
|
||
};
|
||
|
||
-/* Type of stack check. */
|
||
+/* Type of stack check.
|
||
+
|
||
+ Stack checking is designed to detect infinite recursion and stack
|
||
+ overflows for Ada programs. Furthermore stack checking tries to ensure
|
||
+ in that scenario that enough stack space is left to run a signal handler.
|
||
+
|
||
+ -fstack-check= does not prevent stack-clash style attacks. For that
|
||
+ you want -fstack-clash-protection. */
|
||
enum stack_check_type
|
||
{
|
||
/* Do not check the stack. */
|
||
diff -N -urp a/gcc/function.c b/gcc/function.c
|
||
--- a/gcc/function.c 2017-08-08 21:21:12.755378000 +0800
|
||
+++ b/gcc/function.c 2019-01-10 17:07:17.414523742 +0800
|
||
@@ -5695,6 +5695,58 @@ get_arg_pointer_save_area (void)
|
||
return ret;
|
||
}
|
||
|
||
+
|
||
+/* If debugging dumps are requested, dump information about how the
|
||
+ target handled -fstack-check=clash for the prologue.
|
||
+
|
||
+ PROBES describes what if any probes were emitted.
|
||
+
|
||
+ RESIDUALS indicates if the prologue had any residual allocation
|
||
+ (i.e. total allocation was not a multiple of PROBE_INTERVAL). */
|
||
+
|
||
+void
|
||
+dump_stack_clash_frame_info (enum stack_clash_probes probes, bool residuals)
|
||
+{
|
||
+ if (!dump_file)
|
||
+ return;
|
||
+
|
||
+ switch (probes)
|
||
+ {
|
||
+ case NO_PROBE_NO_FRAME:
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash no probe no stack adjustment in prologue.\n");
|
||
+ break;
|
||
+ case NO_PROBE_SMALL_FRAME:
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash no probe small stack adjustment in prologue.\n");
|
||
+ break;
|
||
+ case PROBE_INLINE:
|
||
+ fprintf (dump_file, "Stack clash inline probes in prologue.\n");
|
||
+ break;
|
||
+ case PROBE_LOOP:
|
||
+ fprintf (dump_file, "Stack clash probe loop in prologue.\n");
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (residuals)
|
||
+ fprintf (dump_file, "Stack clash residual allocation in prologue.\n");
|
||
+ else
|
||
+ fprintf (dump_file, "Stack clash no residual allocation in prologue.\n");
|
||
+
|
||
+ if (frame_pointer_needed)
|
||
+ fprintf (dump_file, "Stack clash frame pointer needed.\n");
|
||
+ else
|
||
+ fprintf (dump_file, "Stack clash no frame pointer needed.\n");
|
||
+
|
||
+ if (TREE_THIS_VOLATILE (cfun->decl))
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash noreturn prologue, assuming no implicit"
|
||
+ " probes in caller.\n");
|
||
+ else
|
||
+ fprintf (dump_file,
|
||
+ "Stack clash not noreturn prologue.\n");
|
||
+}
|
||
+
|
||
/* Add a list of INSNS to the hash HASHP, possibly allocating HASHP
|
||
for the first time. */
|
||
|
||
diff -N -urp a/gcc/function.h b/gcc/function.h
|
||
--- a/gcc/function.h 2017-01-25 01:07:36.015431000 +0800
|
||
+++ b/gcc/function.h 2019-01-10 17:08:12.806525200 +0800
|
||
@@ -553,6 +553,14 @@ do { \
|
||
((TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn) \
|
||
? MAX (FUNCTION_BOUNDARY, 2 * BITS_PER_UNIT) : FUNCTION_BOUNDARY)
|
||
|
||
+enum stack_clash_probes {
|
||
+ NO_PROBE_NO_FRAME,
|
||
+ NO_PROBE_SMALL_FRAME,
|
||
+ PROBE_INLINE,
|
||
+ PROBE_LOOP
|
||
+};
|
||
+
|
||
+extern void dump_stack_clash_frame_info (enum stack_clash_probes, bool);
|
||
|
||
|
||
extern void push_function_context (void);
|
||
diff -N -urp a/gcc/params.def b/gcc/params.def
|
||
--- a/gcc/params.def 2019-01-10 13:33:20.894185827 +0800
|
||
+++ b/gcc/params.def 2019-01-10 16:43:15.414485782 +0800
|
||
@@ -213,6 +213,16 @@ DEFPARAM(PARAM_STACK_FRAME_GROWTH,
|
||
"Maximal stack frame growth due to inlining (in percent).",
|
||
1000, 0, 0)
|
||
|
||
+DEFPARAM(PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE,
|
||
+ "stack-clash-protection-guard-size",
|
||
+ "Size of the stack guard expressed as a power of two.",
|
||
+ 12, 12, 30)
|
||
+
|
||
+DEFPARAM(PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL,
|
||
+ "stack-clash-protection-probe-interval",
|
||
+ "Interval in which to probe the stack expressed as a power of two.",
|
||
+ 12, 10, 16)
|
||
+
|
||
/* The GCSE optimization will be disabled if it would require
|
||
significantly more memory than this value. */
|
||
DEFPARAM(PARAM_MAX_GCSE_MEMORY,
|
||
diff -N -urp a/gcc/reg-notes.def b/gcc/reg-notes.def
|
||
--- a/gcc/reg-notes.def 2017-03-28 05:00:35.674561000 +0800
|
||
+++ b/gcc/reg-notes.def 2019-01-10 17:12:11.678531488 +0800
|
||
@@ -223,6 +223,10 @@ REG_NOTE (ARGS_SIZE)
|
||
pseudo reg. */
|
||
REG_NOTE (RETURNED)
|
||
|
||
+/* Indicates the instruction is a stack check probe that should not
|
||
+ be combined with other stack adjustments. */
|
||
+REG_NOTE (STACK_CHECK)
|
||
+
|
||
/* Used to mark a call with the function decl called by the call.
|
||
The decl might not be available in the call due to splitting of the call
|
||
insn. This note is a SYMBOL_REF. */
|
||
diff -N -urp a/gcc/rtl.h b/gcc/rtl.h
|
||
--- a/gcc/rtl.h 2017-03-14 20:47:42.745690000 +0800
|
||
+++ b/gcc/rtl.h 2019-01-10 16:59:15.574511058 +0800
|
||
@@ -2707,6 +2707,7 @@ get_full_set_src_cost (rtx x, machine_mo
|
||
/* In explow.c */
|
||
extern HOST_WIDE_INT trunc_int_for_mode (HOST_WIDE_INT, machine_mode);
|
||
extern rtx plus_constant (machine_mode, rtx, HOST_WIDE_INT, bool = false);
|
||
+extern HOST_WIDE_INT get_stack_check_protect (void);
|
||
|
||
/* In rtl.c */
|
||
extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
|
||
diff -N -urp a/gcc/sched-deps.c b/gcc/sched-deps.c
|
||
--- a/gcc/sched-deps.c 2017-01-01 20:07:43.905435000 +0800
|
||
+++ b/gcc/sched-deps.c 2019-01-10 17:13:37.470533746 +0800
|
||
@@ -4717,6 +4717,11 @@ parse_add_or_inc (struct mem_inc_info *m
|
||
if (RTX_FRAME_RELATED_P (insn) || !pat)
|
||
return false;
|
||
|
||
+ /* Do not allow breaking data dependencies for insns that are marked
|
||
+ with REG_STACK_CHECK. */
|
||
+ if (find_reg_note (insn, REG_STACK_CHECK, NULL))
|
||
+ return false;
|
||
+
|
||
/* Result must be single reg. */
|
||
if (!REG_P (SET_DEST (pat)))
|
||
return false;
|
||
diff -N -urp a/gcc/target.def b/gcc/target.def
|
||
--- a/gcc/target.def 2019-01-10 13:33:20.762185824 +0800
|
||
+++ b/gcc/target.def 2019-01-10 17:01:49.146515100 +0800
|
||
@@ -5490,6 +5490,12 @@ these registers when the target switches
|
||
void, (void),
|
||
hook_void_void)
|
||
|
||
+DEFHOOK
|
||
+(stack_clash_protection_final_dynamic_probe,
|
||
+ "Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero.",
|
||
+ bool, (rtx residual),
|
||
+ default_stack_clash_protection_final_dynamic_probe)
|
||
+
|
||
/* Functions specific to the C family of frontends. */
|
||
#undef HOOK_PREFIX
|
||
#define HOOK_PREFIX "TARGET_C_"
|
||
diff -N -urp a/gcc/targhooks.c b/gcc/targhooks.c
|
||
--- a/gcc/targhooks.c 2017-02-07 19:29:06.644837000 +0800
|
||
+++ b/gcc/targhooks.c 2019-01-10 17:03:23.818517592 +0800
|
||
@@ -2107,4 +2107,10 @@ default_excess_precision (enum excess_pr
|
||
return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT;
|
||
}
|
||
|
||
+bool
|
||
+default_stack_clash_protection_final_dynamic_probe (rtx residual ATTRIBUTE_UNUSED)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
#include "gt-targhooks.h"
|
||
diff -N -urp a/gcc/targhooks.h b/gcc/targhooks.h
|
||
--- a/gcc/targhooks.h 2017-04-05 01:52:27.193766000 +0800
|
||
+++ b/gcc/targhooks.h 2019-01-10 17:04:11.438518846 +0800
|
||
@@ -263,5 +263,6 @@ extern unsigned int default_min_arithmet
|
||
|
||
extern enum flt_eval_method
|
||
default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED);
|
||
+extern bool default_stack_clash_protection_final_dynamic_probe (rtx);
|
||
|
||
#endif /* GCC_TARGHOOKS_H */
|
||
diff -N -urp a/gcc/toplev.c b/gcc/toplev.c
|
||
--- a/gcc/toplev.c 2017-09-15 16:18:34.015147000 +0800
|
||
+++ b/gcc/toplev.c 2019-01-10 16:45:33.626489420 +0800
|
||
@@ -1573,6 +1573,26 @@ process_options (void)
|
||
flag_associative_math = 0;
|
||
}
|
||
|
||
+ /* -fstack-clash-protection is not currently supported on targets
|
||
+ where the stack grows up. */
|
||
+ if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD)
|
||
+ {
|
||
+ warning_at (UNKNOWN_LOCATION, 0,
|
||
+ "%<-fstack-clash-protection%> is not supported on targets "
|
||
+ "where the stack grows from lower to higher addresses");
|
||
+ flag_stack_clash_protection = 0;
|
||
+ }
|
||
+
|
||
+ /* We can not support -fstack-check= and -fstack-clash-protection at
|
||
+ the same time. */
|
||
+ if (flag_stack_check != NO_STACK_CHECK && flag_stack_clash_protection)
|
||
+ {
|
||
+ warning_at (UNKNOWN_LOCATION, 0,
|
||
+ "%<-fstack-check=%> and %<-fstack-clash_protection%> are "
|
||
+ "mutually exclusive. Disabling %<-fstack-check=%>");
|
||
+ flag_stack_check = NO_STACK_CHECK;
|
||
+ }
|
||
+
|
||
/* With -fcx-limited-range, we do cheap and quick complex arithmetic. */
|
||
if (flag_cx_limited_range)
|
||
flag_complex_method = 0;
|