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;