From cd0b2d361df82c848dc7e1c3078651bb0624c3c6 Mon Sep 17 00:00:00 2001 From: Ramana Radhakrishnan Date: Fri, 18 Jan 2019 10:32:40 +0000 Subject: [PATCH] [AArch64] Add support for system register based stack protector canary access 2019-01-18 Ramana Radhakrishnan * config/aarch64/aarch64-opts.h (enum stack_protector_guard): New * config/aarch64/aarch64.c (aarch64_override_options_internal): Handle and put in error checks for stack protector guard options. (aarch64_stack_protect_guard): New. (TARGET_STACK_PROTECT_GUARD): Define. * config/aarch64/aarch64.md (UNSPEC_SSP_SYSREG): New. (reg_stack_protect_address): New. (stack_protect_set): Adjust for SSP_GLOBAL. (stack_protect_test): Likewise. * config/aarch64/aarch64.opt (-mstack-protector-guard-reg): New. (-mstack-protector-guard): Likewise. (-mstack-protector-guard-offset): Likewise. From-SVN: r268068 --- gcc/ChangeLog | 15 ++++++++ gcc/config/aarch64/aarch64-opts.h | 6 +++ gcc/config/aarch64/aarch64.c | 51 ++++++++++++++++++++++++ gcc/config/aarch64/aarch64.md | 64 +++++++++++++++++++++++++++++-- gcc/config/aarch64/aarch64.opt | 30 +++++++++++++++ gcc/doc/invoke.texi | 40 ++++++++++++++++++- 6 files changed, 201 insertions(+), 5 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a16deb68153..6dbff4b0821 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2019-01-18 Ramana Radhakrishnan + + * config/aarch64/aarch64-opts.h (enum stack_protector_guard): New + * config/aarch64/aarch64.c (aarch64_override_options_internal): Handle + and put in error checks for stack protector guard options. + (aarch64_stack_protect_guard): New. + (TARGET_STACK_PROTECT_GUARD): Define. + * config/aarch64/aarch64.md (UNSPEC_SSP_SYSREG): New. + (reg_stack_protect_address): New. + (stack_protect_set): Adjust for SSP_GLOBAL. + (stack_protect_test): Likewise. + * config/aarch64/aarch64.opt (-mstack-protector-guard-reg): New. + (-mstack-protector-guard): Likewise. + (-mstack-protector-guard-offset): Likewise. + 2019-01-18 Jakub Jelinek PR tree-optimization/86214 diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h index 7982de1f5c6..4b07d296a11 100644 --- a/gcc/config/aarch64/aarch64-opts.h +++ b/gcc/config/aarch64/aarch64-opts.h @@ -92,4 +92,10 @@ enum aarch64_sve_vector_bits_enum { SVE_2048 = 2048 }; +/* Where to get the canary for the stack protector. */ +enum stack_protector_guard { + SSP_SYSREG, /* per-thread canary in special system register */ + SSP_GLOBAL /* global canary */ +}; + #endif diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 7eb9316d466..e13badaf6cf 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -11409,6 +11409,41 @@ aarch64_override_options_internal (struct gcc_options *opts) if (opts->x_flag_strict_volatile_bitfields < 0 && abi_version_at_least (2)) opts->x_flag_strict_volatile_bitfields = 1; + if (aarch64_stack_protector_guard == SSP_GLOBAL + && opts->x_aarch64_stack_protector_guard_offset_str) + { + error ("incompatible options -mstack-protector-guard=global and" + "-mstack-protector-guard-offset=%qs", + aarch64_stack_protector_guard_offset_str); + } + + if (aarch64_stack_protector_guard == SSP_SYSREG + && !(opts->x_aarch64_stack_protector_guard_offset_str + && opts->x_aarch64_stack_protector_guard_reg_str)) + { + error ("both -mstack-protector-guard-offset and " + "-mstack-protector-guard-reg must be used " + "with -mstack-protector-guard=sysreg"); + } + + if (opts->x_aarch64_stack_protector_guard_reg_str) + { + if (strlen (opts->x_aarch64_stack_protector_guard_reg_str) > 100) + error ("specify a system register with a small string length."); + } + + if (opts->x_aarch64_stack_protector_guard_offset_str) + { + char *end; + const char *str = aarch64_stack_protector_guard_offset_str; + errno = 0; + long offs = strtol (aarch64_stack_protector_guard_offset_str, &end, 0); + if (!*str || *end || errno) + error ("%qs is not a valid offset in %qs", str, + "-mstack-protector-guard-offset="); + aarch64_stack_protector_guard_offset = offs; + } + initialize_aarch64_code_model (opts); initialize_aarch64_tls_size (opts); @@ -18671,8 +18706,24 @@ aarch64_run_selftests (void) } // namespace selftest +/* Implement TARGET_STACK_PROTECT_GUARD. In case of a + global variable based guard use the default else + return a null tree. */ +static tree +aarch64_stack_protect_guard (void) +{ + if (aarch64_stack_protector_guard == SSP_GLOBAL) + return default_stack_protect_guard (); + + return NULL_TREE; +} + + #endif /* #if CHECKING_P */ +#undef TARGET_STACK_PROTECT_GUARD +#define TARGET_STACK_PROTECT_GUARD aarch64_stack_protect_guard + #undef TARGET_ADDRESS_COST #define TARGET_ADDRESS_COST aarch64_address_cost diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 522c7748443..b7f6fe0f135 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -201,6 +201,7 @@ UNSPEC_UCVTF UNSPEC_USHL_2S UNSPEC_VSTRUCTDUMMY + UNSPEC_SSP_SYSREG UNSPEC_SP_SET UNSPEC_SP_TEST UNSPEC_RSQRT @@ -6774,13 +6775,46 @@ "" { machine_mode mode = GET_MODE (operands[0]); + if (aarch64_stack_protector_guard != SSP_GLOBAL) + { + /* Generate access through the system register. */ + rtx tmp_reg = gen_reg_rtx (mode); + if (mode == DImode) + { + emit_insn (gen_reg_stack_protect_address_di (tmp_reg)); + emit_insn (gen_adddi3 (tmp_reg, tmp_reg, + GEN_INT (aarch64_stack_protector_guard_offset))); + } + else + { + emit_insn (gen_reg_stack_protect_address_si (tmp_reg)); + emit_insn (gen_addsi3 (tmp_reg, tmp_reg, + GEN_INT (aarch64_stack_protector_guard_offset))); + } + operands[1] = gen_rtx_MEM (mode, tmp_reg); + } + emit_insn ((mode == DImode ? gen_stack_protect_set_di : gen_stack_protect_set_si) (operands[0], operands[1])); DONE; }) +(define_insn "reg_stack_protect_address_" + [(set (match_operand:PTR 0 "register_operand" "=r") + (unspec:PTR [(const_int 0)] + UNSPEC_SSP_SYSREG))] + "aarch64_stack_protector_guard != SSP_GLOBAL" + { + char buf[150]; + snprintf (buf, 150, "mrs\\t%%0, %s", + aarch64_stack_protector_guard_reg_str); + output_asm_insn (buf, operands); + return ""; + } + [(set_attr "type" "mrs")]) + (define_insn "stack_protect_set_" [(set (match_operand:PTR 0 "memory_operand" "=m") (unspec:PTR [(match_operand:PTR 1 "memory_operand" "m")] @@ -6801,12 +6835,34 @@ machine_mode mode = GET_MODE (operands[0]); result = gen_reg_rtx(mode); + if (aarch64_stack_protector_guard != SSP_GLOBAL) + { + /* Generate access through the system register. The + sequence we want here is the access + of the stack offset to come with + mrs scratch_reg, + add scratch_reg, scratch_reg, :lo12:offset. */ + rtx tmp_reg = gen_reg_rtx (mode); + if (mode == DImode) + { + emit_insn (gen_reg_stack_protect_address_di (tmp_reg)); + emit_insn (gen_adddi3 (tmp_reg, tmp_reg, + GEN_INT (aarch64_stack_protector_guard_offset))); + } + else + { + emit_insn (gen_reg_stack_protect_address_si (tmp_reg)); + emit_insn (gen_addsi3 (tmp_reg, tmp_reg, + GEN_INT (aarch64_stack_protector_guard_offset))); + } + operands[1] = gen_rtx_MEM (mode, tmp_reg); + } emit_insn ((mode == DImode - ? gen_stack_protect_test_di - : gen_stack_protect_test_si) (result, - operands[0], - operands[1])); + ? gen_stack_protect_test_di + : gen_stack_protect_test_si) (result, + operands[0], + operands[1])); if (mode == DImode) emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx), diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 6de7b225f22..5a1e687091c 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -225,3 +225,33 @@ Enables verbose cost model dumping in the debug dump files. mtrack-speculation Target Var(aarch64_track_speculation) Generate code to track when the CPU might be speculating incorrectly. + +mstack-protector-guard= +Target RejectNegative Joined Enum(stack_protector_guard) Var(aarch64_stack_protector_guard) Init(SSP_GLOBAL) +Use given stack-protector guard. + +Enum +Name(stack_protector_guard) Type(enum stack_protector_guard) +Valid arguments to -mstack-protector-guard=: + +EnumValue +Enum(stack_protector_guard) String(sysreg) Value(SSP_SYSREG) + +EnumValue +Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL) + +mstack-protector-guard-reg= +Target Joined RejectNegative String Var(aarch64_stack_protector_guard_reg_str) +Use the system register specified on the command line as the stack protector +guard register. This option is for use with fstack-protector-strong and +not for use in user-land code. + +mstack-protector-guard-offset= +Target Joined RejectNegative String Var(aarch64_stack_protector_guard_offset_str) +Use an immediate to offset from the stack protector guard register, sp_el0. +This option is for use with fstack-protector-strong and not for use in +user-land code. + +TargetVariable +long aarch64_stack_protector_guard_offset = 0 + diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1151708aaf0..9997dcb7bb2 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -633,7 +633,9 @@ Objective-C and Objective-C++ Dialects}. -msign-return-address=@var{scope} @gol -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}] @gol -march=@var{name} -mcpu=@var{name} -mtune=@var{name} @gol --moverride=@var{string} -mverbose-cost-dump -mtrack-speculation} +-moverride=@var{string} -mverbose-cost-dump @gol +-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{sysreg} @gol +-mstack-protector-guard-offset=@var{offset} -mtrack-speculation } @emph{Adapteva Epiphany Options} @gccoptlist{-mhalf-reg-file -mprefer-short-insn-regs @gol @@ -15606,6 +15608,42 @@ object boundary as described in the architecture specification. Omit or keep the frame pointer in leaf functions. The former behavior is the default. +@item -mstack-protector-guard=@var{guard} +@itemx -mstack-protector-guard-reg=@var{reg} +@itemx -mstack-protector-guard-offset=@var{offset} +@opindex mstack-protector-guard +@opindex mstack-protector-guard-reg +@opindex mstack-protector-guard-offset +Generate stack protection code using canary at @var{guard}. Supported +locations are @samp{global} for a global canary or @samp{sysreg} for a +canary in an appropriate system register. + +With the latter choice the options +@option{-mstack-protector-guard-reg=@var{reg}} and +@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify +which system register to use as base register for reading the canary, +and from what offset from that base register. There is no default +register or offset as this is entirely for use within the Linux +kernel. + +@item -mstack-protector-guard=@var{guard} +@itemx -mstack-protector-guard-reg=@var{reg} +@itemx -mstack-protector-guard-offset=@var{offset} +@opindex mstack-protector-guard +@opindex mstack-protector-guard-reg +@opindex mstack-protector-guard-offset +Generate stack protection code using canary at @var{guard}. Supported +locations are @samp{global} for a global canary or @samp{sysreg} for a +canary in an appropriate system register. + +With the latter choice the options +@option{-mstack-protector-guard-reg=@var{reg}} and +@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify +which system register to use as base register for reading the canary, +and from what offset from that base register. There is no default +register or offset as this is entirely for use within the Linux +kernel. + @item -mtls-dialect=desc @opindex mtls-dialect=desc Use TLS descriptors as the thread-local storage mechanism for dynamic accesses -- 2.30.2