[PATCH v2] [RISC-V] Add support for TLS stack protector canary access

Kito Cheng kito.cheng@gmail.com
Tue Jul 21 08:14:31 GMT 2020


Hi Cooper:

Could you add testcases like ppc[3-4]?

[3] https://github.com/gcc-mirror/gcc/blob/master/gcc/testsuite/gcc.target/powerpc/ssp-1.c
[4] https://github.com/gcc-mirror/gcc/blob/master/gcc/testsuite/gcc.target/powerpc/ssp-2.c

On Mon, Jul 20, 2020 at 10:04 AM cooper via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Ping
>
> On 2020/7/13 下午4:15, cooper wrote:
> > gcc/
> >       * config/riscv/riscv-opts.h (stack_protector_guard): New enum.
> >       * config/riscv/riscv.c (riscv_option_override): Handle
> >       the new options.
> >       * config/riscv/riscv.md (stack_protect_set): New pattern to handle
> >       flexible stack protector guard settings.
> >       (stack_protect_set_<mode>): Ditto.
> >       (stack_protect_test): Ditto.
> >       (stack_protect_test_<mode>): Ditto.
> >       * config/riscv/riscv.opt (mstack-protector-guard=,
> >       mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
> >       options.
> >       * doc/invoke.texi (Option Summary) [RISC-V Options]:
> >       Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
> >       -mstack-protector-guard-offset=.
> >       (RISC-V Options): Ditto.
> >
> > Signed-off-by: cooper <cooper.qu@linux.alibaba.com>
> > Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> > ---
> >   gcc/config/riscv/riscv-opts.h |  6 +++
> >   gcc/config/riscv/riscv.c      | 47 ++++++++++++++++++++
> >   gcc/config/riscv/riscv.md     | 80 +++++++++++++++++++++++++++++++++++
> >   gcc/config/riscv/riscv.opt    | 28 ++++++++++++
> >   gcc/doc/invoke.texi           | 22 +++++++++-
> >   5 files changed, 182 insertions(+), 1 deletion(-)
> >
> > diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
> > index 8f12e50b9f1..2a3f9d9eef5 100644
> > --- a/gcc/config/riscv/riscv-opts.h
> > +++ b/gcc/config/riscv/riscv-opts.h
> > @@ -51,4 +51,10 @@ enum riscv_align_data {
> >     riscv_align_data_type_natural
> >   };
> >
> > +/* Where to get the canary for the stack protector.  */
> > +enum stack_protector_guard {
> > +  SSP_TLS,                   /* per-thread canary in TLS block */
> > +  SSP_GLOBAL                 /* global canary */
> > +};
> > +
> >   #endif /* ! GCC_RISCV_OPTS_H */
> > diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
> > index bfb3885ed08..63b0c3877b0 100644
> > --- a/gcc/config/riscv/riscv.c
> > +++ b/gcc/config/riscv/riscv.c
> > @@ -4775,6 +4775,53 @@ riscv_option_override (void)
> >          " [%<-mriscv-attribute%>]");
> >   #endif
> >
> > +  if (riscv_stack_protector_guard == SSP_GLOBAL
> > +      && global_options_set.x_riscv_stack_protector_guard_offset_str)
> > +    {
> > +      error ("incompatible options %<-mstack-protector-guard=global%> and "
> > +          "%<-mstack-protector-guard-offset=%s%>",
> > +          riscv_stack_protector_guard_offset_str);
> > +    }
> > +
> > +  if (riscv_stack_protector_guard == SSP_TLS
> > +      && !(global_options_set.x_riscv_stack_protector_guard_offset_str
> > +        && global_options_set.x_riscv_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 (global_options_set.x_riscv_stack_protector_guard_reg_str)
> > +    {
> > +      const char *str = riscv_stack_protector_guard_reg_str;
> > +      int reg = decode_reg_name (str);
> > +
> > +      if (!IN_RANGE (reg, GP_REG_FIRST + 1, GP_REG_LAST))
> > +     error ("%qs is not a valid base register in %qs", str,
> > +            "-mstack-protector-guard-reg=");
> > +
> > +      riscv_stack_protector_guard_reg = reg;
> > +    }
> > +
> > +  if (global_options_set.x_riscv_stack_protector_guard_offset_str)
> > +    {
> > +      char *end;
> > +      const char *str = riscv_stack_protector_guard_offset_str;
> > +      errno = 0;
> > +      long offs = strtol (riscv_stack_protector_guard_offset_str, &end, 0);
> > +
> > +      if (!*str || *end || errno)
> > +     error ("%qs is not a valid number in %qs", str,
> > +            "-mstack-protector-guard-offset=");
> > +
> > +      if (!SMALL_OPERAND (offs))
> > +     error ("%qs is not a valid offset in %qs", str,
> > +            "-mstack-protector-guard-offset=");
> > +
> > +      riscv_stack_protector_guard_offset = offs;
> > +    }
> > +
> >   }
> >
> >   /* Implement TARGET_CONDITIONAL_REGISTER_USAGE.  */
> > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> > index 95a02ecaa34..f15bad3b29e 100644
> > --- a/gcc/config/riscv/riscv.md
> > +++ b/gcc/config/riscv/riscv.md
> > @@ -65,6 +65,10 @@
> >     UNSPECV_BLOCKAGE
> >     UNSPECV_FENCE
> >     UNSPECV_FENCE_I
> > +
> > +  ;; Stack Smash Protector
> > +  UNSPEC_SSP_SET
> > +  UNSPEC_SSP_TEST
> >   ])
> >
> >   (define_constants
> > @@ -2523,6 +2527,82 @@
> >     ""
> >   {})
> >
> > +;; Named patterns for stack smashing protection.
> > +
> > +(define_expand "stack_protect_set"
> > +  [(match_operand 0 "memory_operand")
> > +   (match_operand 1 "memory_operand")]
> > +  ""
> > +{
> > +  machine_mode mode = GET_MODE (operands[0]);
> > +  if (riscv_stack_protector_guard == SSP_TLS)
> > +  {
> > +    rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
> > +    rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
> > +    rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
> > +    operands[1] = gen_rtx_MEM (Pmode, addr);
> > +  }
> > +
> > +  emit_insn ((mode == DImode
> > +           ? gen_stack_protect_set_di
> > +           : gen_stack_protect_set_si) (operands[0], operands[1]));
> > +  DONE;
> > +})
> > +
> > +;; DO NOT SPLIT THIS PATTERN.  It is important for security reasons that the
> > +;; canary value does not live beyond the life of this sequence.
> > +(define_insn "stack_protect_set_<mode>"
> > +  [(set (match_operand:GPR 0 "memory_operand" "=m")
> > +     (unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")]
> > +      UNSPEC_SSP_SET))
> > +   (set (match_scratch:GPR 2 "=&r") (const_int 0))]
> > +  ""
> > +  "<load>\\t%2, %1\;<store>\\t%2, %0\;li\t%2, 0"
> > +  [(set_attr "length" "12")])
> > +
> > +(define_expand "stack_protect_test"
> > +  [(match_operand 0 "memory_operand")
> > +   (match_operand 1 "memory_operand")
> > +   (match_operand 2)]
> > +  ""
> > +{
> > +  rtx result;
> > +  machine_mode mode = GET_MODE (operands[0]);
> > +
> > +  result = gen_reg_rtx(mode);
> > +  if (riscv_stack_protector_guard == SSP_TLS)
> > +  {
> > +      rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
> > +      rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
> > +      rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
> > +      operands[1] = gen_rtx_MEM (Pmode, addr);
> > +  }
> > +  emit_insn ((mode == DImode
> > +               ? 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),
> > +                                 result, const0_rtx, operands[2]));
> > +  else
> > +    emit_jump_insn (gen_cbranchsi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
> > +                                 result, const0_rtx, operands[2]));
> > +
> > +  DONE;
> > +})
> > +
> > +(define_insn "stack_protect_test_<mode>"
> > +  [(set (match_operand:GPR 0 "register_operand" "=r")
> > +     (unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")
> > +                  (match_operand:GPR 2 "memory_operand" "m")]
> > +      UNSPEC_SSP_TEST))
> > +   (clobber (match_scratch:GPR 3 "=&r"))]
> > +  ""
> > +  "<load>\t%3, %1\;<load>\t%0, %2\;xor\t%0, %3, %0\;li\t%3, 0"
> > +  [(set_attr "length" "12")])
> > +
> >   (include "sync.md")
> >   (include "peephole.md")
> >   (include "pic.md")
> > diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> > index e4bfcb86f51..f01d3ab79c3 100644
> > --- a/gcc/config/riscv/riscv.opt
> > +++ b/gcc/config/riscv/riscv.opt
> > @@ -151,3 +151,31 @@ Enum(riscv_align_data) String(xlen) Value(riscv_align_data_type_xlen)
> >
> >   EnumValue
> >   Enum(riscv_align_data) String(natural) Value(riscv_align_data_type_natural)
> > +
> > +mstack-protector-guard=
> > +Target RejectNegative Joined Enum(stack_protector_guard) Var(riscv_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(tls) Value(SSP_TLS)
> > +
> > +EnumValue
> > +Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
> > +
> > +mstack-protector-guard-reg=
> > +Target RejectNegative Joined Var(riscv_stack_protector_guard_reg_str)
> > +Use the given base register for addressing the stack-protector guard.
> > +
> > +TargetVariable
> > +int riscv_stack_protector_guard_reg = 0
> > +
> > +mstack-protector-guard-offset=
> > +Target RejectNegative Joined Integer Var(riscv_stack_protector_guard_offset_str)
> > +Use the given offset for addressing the stack-protector guard.
> > +
> > +TargetVariable
> > +long riscv_stack_protector_guard_offset = 0
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 09bcc5b0f78..3bb124ae6ed 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -1138,7 +1138,9 @@ See RS/6000 and PowerPC Options.
> >   -mexplicit-relocs  -mno-explicit-relocs @gol
> >   -mrelax  -mno-relax @gol
> >   -mriscv-attribute  -mmo-riscv-attribute @gol
> > --malign-data=@var{type}}
> > +-malign-data=@var{type} @gol
> > ++-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol
> > ++-mstack-protector-guard-offset=@var{offset}}
> >
> >   @emph{RL78 Options}
> >   @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs @gol
> > @@ -25723,6 +25725,24 @@ Control how GCC aligns variables and constants of array, structure, or union
> >   types.  Supported values for @var{type} are @samp{xlen} which uses x register
> >   width as the alignment value, and @samp{natural} which uses natural alignment.
> >   @samp{xlen} 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{tls} for per-thread
> > +canary in the TLS block.
> > +
> > +With the latter choice the options
> > +@option{-mstack-protector-guard-reg=@var{reg}} and
> > +@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
> > +which 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.
> >   @end table
> >
> >   @node RL78 Options


More information about the Gcc-patches mailing list