public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCHv2 0/4] ROP support
@ 2021-05-14  3:34 Bill Schmidt
  2021-05-14  3:34 ` [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags Bill Schmidt
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14  3:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

This is version 2 of the ROP support patch, addressing comments by
Will Schmidt and Segher Boessenkool.  I've attempted to implement
all of your excellent suggestions; otherwise the series is unchanged.
I decided to repost the whole series rather than just the patches
needing further approval, since all have changed.

Add POWER10 support for hashst[p] and hashchk[p] operations.  When
the -mrop-protect option is selected, any function that loads the link
register from memory before returning must have protection in the
prologue and epilogue to ensure the link register save location has
not been compromised.  If -mprivileged is also specified, the
protection instructions generated require supervisor privilege.

The patches are broken up into logical chunks:
 - Option handling
 - Instruction generation
 - Predefined macro handling
 - Test cases

Bootstrapped and tested on a POWER10 system with no regressions.
Tests on a kernel that enables user-space ROP mitigation were
successful.  Is this series ok for trunk?  I would also like to
later backport these patches to GCC for the 11.2 release.

Thanks!
Bill

Bill Schmidt (4):
  rs6000: Add -mrop-protect and -mprivileged flags
  rs6000: Emit ROP-mitigation instructions in prologue and epilogue
  rs6000: Conditionally define __ROP_PROTECT__
  rs6000: Add ROP tests

 gcc/config/rs6000/rs6000-c.c             |  3 +
 gcc/config/rs6000/rs6000-internal.h      |  2 +
 gcc/config/rs6000/rs6000-logue.c         | 74 +++++++++++++++++++++---
 gcc/config/rs6000/rs6000.c               |  4 ++
 gcc/config/rs6000/rs6000.md              | 47 +++++++++++++++
 gcc/config/rs6000/rs6000.opt             |  8 +++
 gcc/doc/invoke.texi                      | 20 ++++++-
 gcc/testsuite/gcc.target/powerpc/rop-1.c | 17 ++++++
 gcc/testsuite/gcc.target/powerpc/rop-2.c | 17 ++++++
 gcc/testsuite/gcc.target/powerpc/rop-3.c | 18 ++++++
 gcc/testsuite/gcc.target/powerpc/rop-4.c | 15 +++++
 gcc/testsuite/gcc.target/powerpc/rop-5.c | 13 +++++
 12 files changed, 229 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-2.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-3.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-4.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-5.c

-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags
  2021-05-14  3:34 [PATCHv2 0/4] ROP support Bill Schmidt
@ 2021-05-14  3:34 ` Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 15:55   ` Segher Boessenkool
  2021-05-14  3:34 ` [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue Bill Schmidt
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14  3:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000.c (rs6000_option_override_internal):
	Disable shrink wrap when inserting ROP-protect instructions.
	* config/rs6000/rs6000.opt (mrop-protect): New option.
	(mprivileged): Likewise.
	* doc/invoke.texi: Document mrop-protect and mprivileged.
---
 gcc/config/rs6000/rs6000.c   |  4 ++++
 gcc/config/rs6000/rs6000.opt |  8 ++++++++
 gcc/doc/invoke.texi          | 20 ++++++++++++++++++--
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index d1b76f6ec41..53a9f5411c7 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -4040,6 +4040,10 @@ rs6000_option_override_internal (bool global_init_p)
       && ((rs6000_isa_flags_explicit & OPTION_MASK_QUAD_MEMORY_ATOMIC) == 0))
     rs6000_isa_flags |= OPTION_MASK_QUAD_MEMORY_ATOMIC;
 
+  /* If we are inserting ROP-protect instructions, disable shrink wrap.  */
+  if (rs6000_rop_protect)
+    flag_shrink_wrap = 0;
+
   /* If we can shrink-wrap the TOC register save separately, then use
      -msave-toc-indirect unless explicitly disabled.  */
   if ((rs6000_isa_flags_explicit & OPTION_MASK_SAVE_TOC_INDIRECT) == 0
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 0dbdf753673..f66ef20a102 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -619,3 +619,11 @@ Generate (do not generate) MMA instructions.
 
 mrelative-jumptables
 Target Undocumented Var(rs6000_relative_jumptables) Init(1) Save
+
+mrop-protect
+Target Var(rs6000_rop_protect) Init(0)
+Enable instructions that guard against return-oriented programming attacks.
+
+mprivileged
+Target Var(rs6000_privileged) Init(0)
+Enable generation of instructions that require privileged state.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 519881509a6..92549524583 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1240,7 +1240,8 @@ See RS/6000 and PowerPC Options.
 -mgnu-attribute  -mno-gnu-attribute @gol
 -mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol
 -mstack-protector-guard-offset=@var{offset} -mprefixed -mno-prefixed @gol
--mpcrel -mno-pcrel -mmma -mno-mmma}
+-mpcrel -mno-pcrel -mmma -mno-mmma -mrop-protect -mno-rop-protect @gol
+-mprivileged -mno-privileged}
 
 @emph{RX Options}
 @gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
@@ -27029,7 +27030,8 @@ following options:
 -mmulhw  -mdlmzb  -mmfpgpr  -mvsx @gol
 -mcrypto  -mhtm  -mpower8-fusion  -mpower8-vector @gol
 -mquad-memory  -mquad-memory-atomic  -mfloat128 @gol
--mfloat128-hardware -mprefixed -mpcrel -mmma}
+-mfloat128-hardware -mprefixed -mpcrel -mmma @gol
+-mrop-protect}
 
 The particular options set for any particular CPU varies between
 compiler versions, depending on what setting seems to produce optimal
@@ -28034,6 +28036,20 @@ store instructions when the option @option{-mcpu=future} is used.
 Generate (do not generate) the MMA instructions when the option
 @option{-mcpu=future} is used.
 
+@item -mrop-protect
+@itemx -mno-rop-protect
+@opindex mrop-protect
+@opindex mno-rop-protect
+Generate (do not generate) ROP protection instructions when the target
+processor supports them.  Currently this option disables the shrink-wrap
+optimization (@option{-fshrink-wrap}).
+
+@item -mprivileged
+@itemx -mno-privileged
+@opindex mprivileged
+@opindex mno-privileged
+Generate (do not generate) instructions for privileged state.
+
 @item -mblock-ops-unaligned-vsx
 @itemx -mno-block-ops-unaligned-vsx
 @opindex block-ops-unaligned-vsx
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue
  2021-05-14  3:34 [PATCHv2 0/4] ROP support Bill Schmidt
  2021-05-14  3:34 ` [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags Bill Schmidt
@ 2021-05-14  3:34 ` Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 18:44   ` Segher Boessenkool
  2021-05-14  3:34 ` [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__ Bill Schmidt
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14  3:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000-internal.h (rs6000_stack): Add
	rop_hash_save_offset and rop_hash_size.
	* config/rs6000/rs6000-logue.c (rs6000_stack_info): Compute
	rop_hash_size and rop_hash_save_offset.
	(debug_stack_info): Dump rop_hash_save_offset and rop_hash_size.
	(rs6000_emit_prologue): Emit hashst[p] in prologue.
	(rs6000_emit_epilogue): Emit hashchk[p] in epilogue.
	* config/rs6000/rs6000.md (unspec): Add UNSPEC_HASHST and
	UNSPEC_HASHCHK.
	(hashst): New define_insn.
	(hashchk): Likewise.
---
 gcc/config/rs6000/rs6000-internal.h |  2 +
 gcc/config/rs6000/rs6000-logue.c    | 74 ++++++++++++++++++++++++++---
 gcc/config/rs6000/rs6000.md         | 47 ++++++++++++++++++
 3 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-internal.h b/gcc/config/rs6000/rs6000-internal.h
index 428a7861a98..88cf9bd5692 100644
--- a/gcc/config/rs6000/rs6000-internal.h
+++ b/gcc/config/rs6000/rs6000-internal.h
@@ -39,6 +39,7 @@ typedef struct rs6000_stack {
   int gp_save_offset;		/* offset to save GP regs from initial SP */
   int fp_save_offset;		/* offset to save FP regs from initial SP */
   int altivec_save_offset;	/* offset to save AltiVec regs from initial SP */
+  int rop_hash_save_offset;	/* offset to save ROP hash from initial SP */
   int lr_save_offset;		/* offset to save LR from initial SP */
   int cr_save_offset;		/* offset to save CR from initial SP */
   int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
@@ -53,6 +54,7 @@ typedef struct rs6000_stack {
   int gp_size;			/* size of saved GP registers */
   int fp_size;			/* size of saved FP registers */
   int altivec_size;		/* size of saved AltiVec registers */
+  int rop_hash_size;		/* size of ROP hash slot */
   int cr_size;			/* size to hold CR if not in fixed area */
   int vrsave_size;		/* size to hold VRSAVE */
   int altivec_padding_size;	/* size of altivec alignment padding */
diff --git a/gcc/config/rs6000/rs6000-logue.c b/gcc/config/rs6000/rs6000-logue.c
index b0ac183ceff..13c00e740d6 100644
--- a/gcc/config/rs6000/rs6000-logue.c
+++ b/gcc/config/rs6000/rs6000-logue.c
@@ -595,19 +595,21 @@ rs6000_savres_strategy (rs6000_stack_t *info,
 		+---------------------------------------+
 		| Parameter save area (+padding*) (P)	|  32
 		+---------------------------------------+
-		| Alloca space (A)			|  32+P
+		| Optional ROP hash slot (R)		|  32+P
 		+---------------------------------------+
-		| Local variable space (L)		|  32+P+A
+		| Alloca space (A)			|  32+P+R
 		+---------------------------------------+
-		| Save area for AltiVec registers (W)	|  32+P+A+L
+		| Local variable space (L)		|  32+P+R+A
 		+---------------------------------------+
-		| AltiVec alignment padding (Y)		|  32+P+A+L+W
+		| Save area for AltiVec registers (W)	|  32+P+R+A+L
 		+---------------------------------------+
-		| Save area for GP registers (G)	|  32+P+A+L+W+Y
+		| AltiVec alignment padding (Y)		|  32+P+R+A+L+W
 		+---------------------------------------+
-		| Save area for FP registers (F)	|  32+P+A+L+W+Y+G
+		| Save area for GP registers (G)	|  32+P+R+A+L+W+Y
 		+---------------------------------------+
-	old SP->| back chain to caller's caller		|  32+P+A+L+W+Y+G+F
+		| Save area for FP registers (F)	|  32+P+R+A+L+W+Y+G
+		+---------------------------------------+
+	old SP->| back chain to caller's caller		|  32+P+R+A+L+W+Y+G+F
 		+---------------------------------------+
 
      * If the alloca area is present, the parameter save area is
@@ -716,6 +718,19 @@ rs6000_stack_info (void)
 
   /* Does this function call anything (apart from sibling calls)?  */
   info->calls_p = (!crtl->is_leaf || cfun->machine->ra_needs_full_frame);
+  info->rop_hash_size = 0;
+
+  if (TARGET_POWER10
+      && info->calls_p
+      && DEFAULT_ABI == ABI_ELFv2
+      && rs6000_rop_protect)
+    info->rop_hash_size = 8;
+  else if (rs6000_rop_protect && DEFAULT_ABI != ABI_ELFv2)
+    {
+      /* We can't check this in rs6000_option_override_internal since
+	 DEFAULT_ABI isn't established yet.  */
+      error ("%qs requires the ELFv2 ABI", "-mrop-protect");
+    }
 
   /* Determine if we need to save the condition code registers.  */
   if (save_reg_p (CR2_REGNO)
@@ -808,6 +823,11 @@ rs6000_stack_info (void)
 
 	  /* Adjust for AltiVec case.  */
 	  info->ehrd_offset = info->altivec_save_offset - ehrd_size;
+
+	  /* Adjust for ROP protection.  */
+	  info->rop_hash_save_offset
+	    = info->altivec_save_offset - info->rop_hash_size;
+	  info->ehrd_offset -= info->rop_hash_size;
 	}
       else
 	info->ehrd_offset = info->gp_save_offset - ehrd_size;
@@ -849,6 +869,7 @@ rs6000_stack_info (void)
 				  + info->gp_size
 				  + info->altivec_size
 				  + info->altivec_padding_size
+				  + info->rop_hash_size
 				  + ehrd_size
 				  + ehcr_size
 				  + info->cr_size
@@ -987,6 +1008,10 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
 	     info->vrsave_save_offset);
 
+  if (info->rop_hash_size)
+    fprintf (stderr, "\trop_hash_save_offset = %5d\n",
+	     info->rop_hash_save_offset);
+
   if (info->lr_save_p)
     fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
 
@@ -1026,6 +1051,9 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\taltivec_padding_size= %5d\n",
 	     info->altivec_padding_size);
 
+  if (info->rop_hash_size)
+    fprintf (stderr, "\trop_hash_size       = %5d\n", info->rop_hash_size);
+
   if (info->cr_size)
     fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
 
@@ -3252,6 +3280,22 @@ rs6000_emit_prologue (void)
 	}
     }
 
+  /* The ROP hash store must occur before a stack frame is created,
+     since the hash operates on r1.  */
+  /* NOTE: The hashst isn't needed if we're going to do a sibcall,
+     but there's no way to know that here.  Harmless except for
+     performance, of course.  */
+  if (TARGET_POWER10 && rs6000_rop_protect && info->rop_hash_size != 0)
+    {
+      gcc_assert (DEFAULT_ABI == ABI_ELFv2);
+      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+      rtx addr = gen_rtx_PLUS (Pmode, stack_ptr,
+			       GEN_INT (info->rop_hash_save_offset));
+      rtx mem = gen_rtx_MEM (Pmode, addr);
+      rtx reg0 = gen_rtx_REG (Pmode, 0);
+      emit_insn (gen_hashst (mem, reg0));
+    }
+
   /* If we need to save CR, put it into r12 or r11.  Choose r12 except when
      r12 will be needed by out-of-line gpr save.  */
   cr_save_regno = ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
@@ -4980,6 +5024,22 @@ rs6000_emit_epilogue (enum epilogue_type epilogue_type)
       emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx, sa));
     }
 
+  /* The ROP hash check must occur after the stack pointer is restored
+     (since the hash involves r1), and is not performed for a sibcall.  */
+  if (TARGET_POWER10
+      && rs6000_rop_protect
+      && info->rop_hash_size != 0
+      && epilogue_type != EPILOGUE_TYPE_SIBCALL)
+    {
+      gcc_assert (DEFAULT_ABI == ABI_ELFv2);
+      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+      rtx addr = gen_rtx_PLUS (Pmode, stack_ptr,
+			       GEN_INT (info->rop_hash_save_offset));
+      rtx mem = gen_rtx_MEM (Pmode, addr);
+      rtx reg0 = gen_rtx_REG (Pmode, 0);
+      emit_insn (gen_hashchk (reg0, mem));
+    }
+
   if (epilogue_type != EPILOGUE_TYPE_SIBCALL && restoring_FPRs_inline)
     {
       if (cfa_restores)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c8cdc42533c..ce58ecd6b73 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -154,6 +154,8 @@ (define_c_enum "unspec"
    UNSPEC_CNTTZDM
    UNSPEC_PDEPD
    UNSPEC_PEXTD
+   UNSPEC_HASHST
+   UNSPEC_HASHCHK
   ])
 
 ;;
@@ -14948,6 +14950,51 @@ (define_insn "*cmpeqb_internal"
   "TARGET_P9_MISC && TARGET_64BIT"
   "cmpeqb %0,%1,%2"
   [(set_attr "type" "logical")])
+
+
+;; ROP mitigation instructions.
+
+(define_insn "hashst"
+  [(set (match_operand:DI 0 "simple_offsettable_mem_operand" "=m")
+        (unspec:DI [(match_operand:DI 1 "int_reg_operand" "r")]
+	           UNSPEC_HASHST))]
+  "TARGET_POWER10 && rs6000_rop_protect"
+{
+  static char templ[14];
+  char p[2];
+
+  if (rs6000_privileged)
+    {
+      p[0] = 'p';
+      p[1] = 0;
+    }
+  else
+    p[0] = 0;
+  sprintf (templ, "hashst%s %%1,%%0", p);
+  return templ;
+}
+  [(set_attr "type" "store")])
+
+(define_insn "hashchk"
+  [(unspec_volatile [(match_operand:DI 0 "int_reg_operand" "r")
+		     (match_operand:DI 1 "simple_offsettable_mem_operand" "m")]
+		    UNSPEC_HASHCHK)]
+  "TARGET_POWER10 && rs6000_rop_protect"
+{
+  static char templ[15];
+  char p[2];
+
+  if (rs6000_privileged)
+    {
+      p[0] = 'p';
+      p[1] = 0;
+    }
+  else
+    p[0] = 0;
+  sprintf (templ, "hashchk%s %%0,%%1", p);
+  return templ;
+}
+  [(set_attr "type" "load")])
 \f
 
 (include "sync.md")
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__
  2021-05-14  3:34 [PATCHv2 0/4] ROP support Bill Schmidt
  2021-05-14  3:34 ` [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags Bill Schmidt
  2021-05-14  3:34 ` [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue Bill Schmidt
@ 2021-05-14  3:34 ` Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 18:51   ` Segher Boessenkool
  2021-05-14  3:34 ` [PATCH 4/4] rs6000: Add ROP tests Bill Schmidt
  2021-05-14 14:18 ` [PATCHv2 0/4] ROP support Bill Schmidt
  4 siblings, 2 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14  3:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000-c.c (rs6000_target_modify_macros): Define
	__ROP_PROTECT__ if -mrop-protect is selected.
---
 gcc/config/rs6000/rs6000-c.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index 0f8a629ff5a..afcb5bb6e39 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -602,6 +602,9 @@ rs6000_target_modify_macros (bool define_p, HOST_WIDE_INT flags,
   /* Whether pc-relative code is being generated.  */
   if ((flags & OPTION_MASK_PCREL) != 0)
     rs6000_define_or_undefine_macro (define_p, "__PCREL__");
+  /* Tell the user -mrop-protect is in play.  */
+  if (rs6000_rop_protect)
+    rs6000_define_or_undefine_macro (define_p, "__ROP_PROTECT__");
 }
 
 void
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 4/4] rs6000: Add ROP tests
  2021-05-14  3:34 [PATCHv2 0/4] ROP support Bill Schmidt
                   ` (2 preceding siblings ...)
  2021-05-14  3:34 ` [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__ Bill Schmidt
@ 2021-05-14  3:34 ` Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 19:36   ` Segher Boessenkool
  2021-05-14 14:18 ` [PATCHv2 0/4] ROP support Bill Schmidt
  4 siblings, 2 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14  3:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/testsuite/
	* gcc.target/powerpc/rop-1.c: New.
	* gcc.target/powerpc/rop-2.c: New.
	* gcc.target/powerpc/rop-3.c: New.
	* gcc.target/powerpc/rop-4.c: New.
	* gcc.target/powerpc/rop-5.c: New.
---
 gcc/testsuite/gcc.target/powerpc/rop-1.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-2.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-3.c | 18 ++++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-4.c | 15 +++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-5.c | 13 +++++++++++++
 5 files changed, 80 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-2.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-3.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-4.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-5.c

diff --git a/gcc/testsuite/gcc.target/powerpc/rop-1.c b/gcc/testsuite/gcc.target/powerpc/rop-1.c
new file mode 100644
index 00000000000..8cedcb6668a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify that ROP-protect instructions are inserted when a
+   call is present.  */
+
+extern void foo (void);
+
+int bar ()
+{
+  foo ();
+  return 5;
+}
+
+/* { dg-final { scan-assembler-times {\mhashst\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mhashchk\M} 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-2.c b/gcc/testsuite/gcc.target/powerpc/rop-2.c
new file mode 100644
index 00000000000..c556952aec1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-2.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect -mprivileged" } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify that privileged ROP-protect instructions are inserted when a
+   call is present.  */
+
+extern void foo (void);
+
+int bar ()
+{
+  foo ();
+  return 5;
+}
+
+/* { dg-final { scan-assembler-times {\mhashstp\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mhashchkp\M} 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-3.c b/gcc/testsuite/gcc.target/powerpc/rop-3.c
new file mode 100644
index 00000000000..8d03792e3e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-3.c
@@ -0,0 +1,18 @@
+/* { dg-do run { target { power10_hw } } } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+
+/* Verify that ROP-protect instructions execute correctly when a
+   call is present.  */
+
+void __attribute__((noipa)) foo ()
+{
+  asm ("");
+}
+
+int main ()
+{
+  foo ();
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-4.c b/gcc/testsuite/gcc.target/powerpc/rop-4.c
new file mode 100644
index 00000000000..dcf47c63fb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-4.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify that no ROP-protect instructions are inserted when no
+   call is present.  */
+
+
+int bar ()
+{
+  return 5;
+}
+
+/* { dg-final { scan-assembler-not {\mhashst\M} } } */
+/* { dg-final { scan-assembler-not {\mhashchk\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-5.c b/gcc/testsuite/gcc.target/powerpc/rop-5.c
new file mode 100644
index 00000000000..cf04ea90eeb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+
+/* Verify that __ROP_PROTECT__ is predefined for -mrop-protect.  */
+
+int foo ()
+{
+#ifndef __ROP_PROTECT__
+  __ROP_PROTECT__ macro is not defined when it should be
+#endif
+  return 0;
+}
+
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCHv2 0/4] ROP support
  2021-05-14  3:34 [PATCHv2 0/4] ROP support Bill Schmidt
                   ` (3 preceding siblings ...)
  2021-05-14  3:34 ` [PATCH 4/4] rs6000: Add ROP tests Bill Schmidt
@ 2021-05-14 14:18 ` Bill Schmidt
  4 siblings, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14 14:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

[Pardon the repost, trying to sort out a problem where Segher doesn't
receive my mail from this host.]

This is version 2 of the ROP support patch, addressing comments by
Will Schmidt and Segher Boessenkool.  I've attempted to implement
all of your excellent suggestions; otherwise the series is unchanged.
I decided to repost the whole series rather than just the patches
needing further approval, since all have changed.

Add POWER10 support for hashst[p] and hashchk[p] operations.  When
the -mrop-protect option is selected, any function that loads the link
register from memory before returning must have protection in the
prologue and epilogue to ensure the link register save location has
not been compromised.  If -mprivileged is also specified, the
protection instructions generated require supervisor privilege.

The patches are broken up into logical chunks:
 - Option handling
 - Instruction generation
 - Predefined macro handling
 - Test cases

Bootstrapped and tested on a POWER10 system with no regressions.
Tests on a kernel that enables user-space ROP mitigation were
successful.  Is this series ok for trunk?  I would also like to
later backport these patches to GCC for the 11.2 release.

Thanks!
Bill

Bill Schmidt (4):
  rs6000: Add -mrop-protect and -mprivileged flags
  rs6000: Emit ROP-mitigation instructions in prologue and epilogue
  rs6000: Conditionally define __ROP_PROTECT__
  rs6000: Add ROP tests

 gcc/config/rs6000/rs6000-c.c             |  3 +
 gcc/config/rs6000/rs6000-internal.h      |  2 +
 gcc/config/rs6000/rs6000-logue.c         | 74 +++++++++++++++++++++---
 gcc/config/rs6000/rs6000.c               |  4 ++
 gcc/config/rs6000/rs6000.md              | 47 +++++++++++++++
 gcc/config/rs6000/rs6000.opt             |  8 +++
 gcc/doc/invoke.texi                      | 20 ++++++-
 gcc/testsuite/gcc.target/powerpc/rop-1.c | 17 ++++++
 gcc/testsuite/gcc.target/powerpc/rop-2.c | 17 ++++++
 gcc/testsuite/gcc.target/powerpc/rop-3.c | 18 ++++++
 gcc/testsuite/gcc.target/powerpc/rop-4.c | 15 +++++
 gcc/testsuite/gcc.target/powerpc/rop-5.c | 13 +++++
 12 files changed, 229 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-2.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-3.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-4.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-5.c

-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags
  2021-05-14  3:34 ` [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags Bill Schmidt
@ 2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 15:55   ` Segher Boessenkool
  1 sibling, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14 14:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000.c (rs6000_option_override_internal):
	Disable shrink wrap when inserting ROP-protect instructions.
	* config/rs6000/rs6000.opt (mrop-protect): New option.
	(mprivileged): Likewise.
	* doc/invoke.texi: Document mrop-protect and mprivileged.
---
 gcc/config/rs6000/rs6000.c   |  4 ++++
 gcc/config/rs6000/rs6000.opt |  8 ++++++++
 gcc/doc/invoke.texi          | 20 ++++++++++++++++++--
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index d1b76f6ec41..53a9f5411c7 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -4040,6 +4040,10 @@ rs6000_option_override_internal (bool global_init_p)
       && ((rs6000_isa_flags_explicit & OPTION_MASK_QUAD_MEMORY_ATOMIC) == 0))
     rs6000_isa_flags |= OPTION_MASK_QUAD_MEMORY_ATOMIC;
 
+  /* If we are inserting ROP-protect instructions, disable shrink wrap.  */
+  if (rs6000_rop_protect)
+    flag_shrink_wrap = 0;
+
   /* If we can shrink-wrap the TOC register save separately, then use
      -msave-toc-indirect unless explicitly disabled.  */
   if ((rs6000_isa_flags_explicit & OPTION_MASK_SAVE_TOC_INDIRECT) == 0
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 0dbdf753673..f66ef20a102 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -619,3 +619,11 @@ Generate (do not generate) MMA instructions.
 
 mrelative-jumptables
 Target Undocumented Var(rs6000_relative_jumptables) Init(1) Save
+
+mrop-protect
+Target Var(rs6000_rop_protect) Init(0)
+Enable instructions that guard against return-oriented programming attacks.
+
+mprivileged
+Target Var(rs6000_privileged) Init(0)
+Enable generation of instructions that require privileged state.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 519881509a6..92549524583 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1240,7 +1240,8 @@ See RS/6000 and PowerPC Options.
 -mgnu-attribute  -mno-gnu-attribute @gol
 -mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol
 -mstack-protector-guard-offset=@var{offset} -mprefixed -mno-prefixed @gol
--mpcrel -mno-pcrel -mmma -mno-mmma}
+-mpcrel -mno-pcrel -mmma -mno-mmma -mrop-protect -mno-rop-protect @gol
+-mprivileged -mno-privileged}
 
 @emph{RX Options}
 @gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
@@ -27029,7 +27030,8 @@ following options:
 -mmulhw  -mdlmzb  -mmfpgpr  -mvsx @gol
 -mcrypto  -mhtm  -mpower8-fusion  -mpower8-vector @gol
 -mquad-memory  -mquad-memory-atomic  -mfloat128 @gol
--mfloat128-hardware -mprefixed -mpcrel -mmma}
+-mfloat128-hardware -mprefixed -mpcrel -mmma @gol
+-mrop-protect}
 
 The particular options set for any particular CPU varies between
 compiler versions, depending on what setting seems to produce optimal
@@ -28034,6 +28036,20 @@ store instructions when the option @option{-mcpu=future} is used.
 Generate (do not generate) the MMA instructions when the option
 @option{-mcpu=future} is used.
 
+@item -mrop-protect
+@itemx -mno-rop-protect
+@opindex mrop-protect
+@opindex mno-rop-protect
+Generate (do not generate) ROP protection instructions when the target
+processor supports them.  Currently this option disables the shrink-wrap
+optimization (@option{-fshrink-wrap}).
+
+@item -mprivileged
+@itemx -mno-privileged
+@opindex mprivileged
+@opindex mno-privileged
+Generate (do not generate) instructions for privileged state.
+
 @item -mblock-ops-unaligned-vsx
 @itemx -mno-block-ops-unaligned-vsx
 @opindex block-ops-unaligned-vsx
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue
  2021-05-14  3:34 ` [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue Bill Schmidt
@ 2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 18:44   ` Segher Boessenkool
  1 sibling, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14 14:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000-internal.h (rs6000_stack): Add
	rop_hash_save_offset and rop_hash_size.
	* config/rs6000/rs6000-logue.c (rs6000_stack_info): Compute
	rop_hash_size and rop_hash_save_offset.
	(debug_stack_info): Dump rop_hash_save_offset and rop_hash_size.
	(rs6000_emit_prologue): Emit hashst[p] in prologue.
	(rs6000_emit_epilogue): Emit hashchk[p] in epilogue.
	* config/rs6000/rs6000.md (unspec): Add UNSPEC_HASHST and
	UNSPEC_HASHCHK.
	(hashst): New define_insn.
	(hashchk): Likewise.
---
 gcc/config/rs6000/rs6000-internal.h |  2 +
 gcc/config/rs6000/rs6000-logue.c    | 74 ++++++++++++++++++++++++++---
 gcc/config/rs6000/rs6000.md         | 47 ++++++++++++++++++
 3 files changed, 116 insertions(+), 7 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-internal.h b/gcc/config/rs6000/rs6000-internal.h
index 428a7861a98..88cf9bd5692 100644
--- a/gcc/config/rs6000/rs6000-internal.h
+++ b/gcc/config/rs6000/rs6000-internal.h
@@ -39,6 +39,7 @@ typedef struct rs6000_stack {
   int gp_save_offset;		/* offset to save GP regs from initial SP */
   int fp_save_offset;		/* offset to save FP regs from initial SP */
   int altivec_save_offset;	/* offset to save AltiVec regs from initial SP */
+  int rop_hash_save_offset;	/* offset to save ROP hash from initial SP */
   int lr_save_offset;		/* offset to save LR from initial SP */
   int cr_save_offset;		/* offset to save CR from initial SP */
   int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
@@ -53,6 +54,7 @@ typedef struct rs6000_stack {
   int gp_size;			/* size of saved GP registers */
   int fp_size;			/* size of saved FP registers */
   int altivec_size;		/* size of saved AltiVec registers */
+  int rop_hash_size;		/* size of ROP hash slot */
   int cr_size;			/* size to hold CR if not in fixed area */
   int vrsave_size;		/* size to hold VRSAVE */
   int altivec_padding_size;	/* size of altivec alignment padding */
diff --git a/gcc/config/rs6000/rs6000-logue.c b/gcc/config/rs6000/rs6000-logue.c
index b0ac183ceff..13c00e740d6 100644
--- a/gcc/config/rs6000/rs6000-logue.c
+++ b/gcc/config/rs6000/rs6000-logue.c
@@ -595,19 +595,21 @@ rs6000_savres_strategy (rs6000_stack_t *info,
 		+---------------------------------------+
 		| Parameter save area (+padding*) (P)	|  32
 		+---------------------------------------+
-		| Alloca space (A)			|  32+P
+		| Optional ROP hash slot (R)		|  32+P
 		+---------------------------------------+
-		| Local variable space (L)		|  32+P+A
+		| Alloca space (A)			|  32+P+R
 		+---------------------------------------+
-		| Save area for AltiVec registers (W)	|  32+P+A+L
+		| Local variable space (L)		|  32+P+R+A
 		+---------------------------------------+
-		| AltiVec alignment padding (Y)		|  32+P+A+L+W
+		| Save area for AltiVec registers (W)	|  32+P+R+A+L
 		+---------------------------------------+
-		| Save area for GP registers (G)	|  32+P+A+L+W+Y
+		| AltiVec alignment padding (Y)		|  32+P+R+A+L+W
 		+---------------------------------------+
-		| Save area for FP registers (F)	|  32+P+A+L+W+Y+G
+		| Save area for GP registers (G)	|  32+P+R+A+L+W+Y
 		+---------------------------------------+
-	old SP->| back chain to caller's caller		|  32+P+A+L+W+Y+G+F
+		| Save area for FP registers (F)	|  32+P+R+A+L+W+Y+G
+		+---------------------------------------+
+	old SP->| back chain to caller's caller		|  32+P+R+A+L+W+Y+G+F
 		+---------------------------------------+
 
      * If the alloca area is present, the parameter save area is
@@ -716,6 +718,19 @@ rs6000_stack_info (void)
 
   /* Does this function call anything (apart from sibling calls)?  */
   info->calls_p = (!crtl->is_leaf || cfun->machine->ra_needs_full_frame);
+  info->rop_hash_size = 0;
+
+  if (TARGET_POWER10
+      && info->calls_p
+      && DEFAULT_ABI == ABI_ELFv2
+      && rs6000_rop_protect)
+    info->rop_hash_size = 8;
+  else if (rs6000_rop_protect && DEFAULT_ABI != ABI_ELFv2)
+    {
+      /* We can't check this in rs6000_option_override_internal since
+	 DEFAULT_ABI isn't established yet.  */
+      error ("%qs requires the ELFv2 ABI", "-mrop-protect");
+    }
 
   /* Determine if we need to save the condition code registers.  */
   if (save_reg_p (CR2_REGNO)
@@ -808,6 +823,11 @@ rs6000_stack_info (void)
 
 	  /* Adjust for AltiVec case.  */
 	  info->ehrd_offset = info->altivec_save_offset - ehrd_size;
+
+	  /* Adjust for ROP protection.  */
+	  info->rop_hash_save_offset
+	    = info->altivec_save_offset - info->rop_hash_size;
+	  info->ehrd_offset -= info->rop_hash_size;
 	}
       else
 	info->ehrd_offset = info->gp_save_offset - ehrd_size;
@@ -849,6 +869,7 @@ rs6000_stack_info (void)
 				  + info->gp_size
 				  + info->altivec_size
 				  + info->altivec_padding_size
+				  + info->rop_hash_size
 				  + ehrd_size
 				  + ehcr_size
 				  + info->cr_size
@@ -987,6 +1008,10 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
 	     info->vrsave_save_offset);
 
+  if (info->rop_hash_size)
+    fprintf (stderr, "\trop_hash_save_offset = %5d\n",
+	     info->rop_hash_save_offset);
+
   if (info->lr_save_p)
     fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
 
@@ -1026,6 +1051,9 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\taltivec_padding_size= %5d\n",
 	     info->altivec_padding_size);
 
+  if (info->rop_hash_size)
+    fprintf (stderr, "\trop_hash_size       = %5d\n", info->rop_hash_size);
+
   if (info->cr_size)
     fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
 
@@ -3252,6 +3280,22 @@ rs6000_emit_prologue (void)
 	}
     }
 
+  /* The ROP hash store must occur before a stack frame is created,
+     since the hash operates on r1.  */
+  /* NOTE: The hashst isn't needed if we're going to do a sibcall,
+     but there's no way to know that here.  Harmless except for
+     performance, of course.  */
+  if (TARGET_POWER10 && rs6000_rop_protect && info->rop_hash_size != 0)
+    {
+      gcc_assert (DEFAULT_ABI == ABI_ELFv2);
+      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+      rtx addr = gen_rtx_PLUS (Pmode, stack_ptr,
+			       GEN_INT (info->rop_hash_save_offset));
+      rtx mem = gen_rtx_MEM (Pmode, addr);
+      rtx reg0 = gen_rtx_REG (Pmode, 0);
+      emit_insn (gen_hashst (mem, reg0));
+    }
+
   /* If we need to save CR, put it into r12 or r11.  Choose r12 except when
      r12 will be needed by out-of-line gpr save.  */
   cr_save_regno = ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
@@ -4980,6 +5024,22 @@ rs6000_emit_epilogue (enum epilogue_type epilogue_type)
       emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx, sa));
     }
 
+  /* The ROP hash check must occur after the stack pointer is restored
+     (since the hash involves r1), and is not performed for a sibcall.  */
+  if (TARGET_POWER10
+      && rs6000_rop_protect
+      && info->rop_hash_size != 0
+      && epilogue_type != EPILOGUE_TYPE_SIBCALL)
+    {
+      gcc_assert (DEFAULT_ABI == ABI_ELFv2);
+      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+      rtx addr = gen_rtx_PLUS (Pmode, stack_ptr,
+			       GEN_INT (info->rop_hash_save_offset));
+      rtx mem = gen_rtx_MEM (Pmode, addr);
+      rtx reg0 = gen_rtx_REG (Pmode, 0);
+      emit_insn (gen_hashchk (reg0, mem));
+    }
+
   if (epilogue_type != EPILOGUE_TYPE_SIBCALL && restoring_FPRs_inline)
     {
       if (cfa_restores)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c8cdc42533c..ce58ecd6b73 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -154,6 +154,8 @@ (define_c_enum "unspec"
    UNSPEC_CNTTZDM
    UNSPEC_PDEPD
    UNSPEC_PEXTD
+   UNSPEC_HASHST
+   UNSPEC_HASHCHK
   ])
 
 ;;
@@ -14948,6 +14950,51 @@ (define_insn "*cmpeqb_internal"
   "TARGET_P9_MISC && TARGET_64BIT"
   "cmpeqb %0,%1,%2"
   [(set_attr "type" "logical")])
+
+
+;; ROP mitigation instructions.
+
+(define_insn "hashst"
+  [(set (match_operand:DI 0 "simple_offsettable_mem_operand" "=m")
+        (unspec:DI [(match_operand:DI 1 "int_reg_operand" "r")]
+	           UNSPEC_HASHST))]
+  "TARGET_POWER10 && rs6000_rop_protect"
+{
+  static char templ[14];
+  char p[2];
+
+  if (rs6000_privileged)
+    {
+      p[0] = 'p';
+      p[1] = 0;
+    }
+  else
+    p[0] = 0;
+  sprintf (templ, "hashst%s %%1,%%0", p);
+  return templ;
+}
+  [(set_attr "type" "store")])
+
+(define_insn "hashchk"
+  [(unspec_volatile [(match_operand:DI 0 "int_reg_operand" "r")
+		     (match_operand:DI 1 "simple_offsettable_mem_operand" "m")]
+		    UNSPEC_HASHCHK)]
+  "TARGET_POWER10 && rs6000_rop_protect"
+{
+  static char templ[15];
+  char p[2];
+
+  if (rs6000_privileged)
+    {
+      p[0] = 'p';
+      p[1] = 0;
+    }
+  else
+    p[0] = 0;
+  sprintf (templ, "hashchk%s %%0,%%1", p);
+  return templ;
+}
+  [(set_attr "type" "load")])
 \f
 
 (include "sync.md")
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__
  2021-05-14  3:34 ` [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__ Bill Schmidt
@ 2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 18:51   ` Segher Boessenkool
  1 sibling, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14 14:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000-c.c (rs6000_target_modify_macros): Define
	__ROP_PROTECT__ if -mrop-protect is selected.
---
 gcc/config/rs6000/rs6000-c.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index 0f8a629ff5a..afcb5bb6e39 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -602,6 +602,9 @@ rs6000_target_modify_macros (bool define_p, HOST_WIDE_INT flags,
   /* Whether pc-relative code is being generated.  */
   if ((flags & OPTION_MASK_PCREL) != 0)
     rs6000_define_or_undefine_macro (define_p, "__PCREL__");
+  /* Tell the user -mrop-protect is in play.  */
+  if (rs6000_rop_protect)
+    rs6000_define_or_undefine_macro (define_p, "__ROP_PROTECT__");
 }
 
 void
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 4/4] rs6000: Add ROP tests
  2021-05-14  3:34 ` [PATCH 4/4] rs6000: Add ROP tests Bill Schmidt
@ 2021-05-14 14:18   ` Bill Schmidt
  2021-05-14 19:36   ` Segher Boessenkool
  1 sibling, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14 14:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, dje.gcc, Bill Schmidt

2021-05-13  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/testsuite/
	* gcc.target/powerpc/rop-1.c: New.
	* gcc.target/powerpc/rop-2.c: New.
	* gcc.target/powerpc/rop-3.c: New.
	* gcc.target/powerpc/rop-4.c: New.
	* gcc.target/powerpc/rop-5.c: New.
---
 gcc/testsuite/gcc.target/powerpc/rop-1.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-2.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-3.c | 18 ++++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-4.c | 15 +++++++++++++++
 gcc/testsuite/gcc.target/powerpc/rop-5.c | 13 +++++++++++++
 5 files changed, 80 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-2.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-3.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-4.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/rop-5.c

diff --git a/gcc/testsuite/gcc.target/powerpc/rop-1.c b/gcc/testsuite/gcc.target/powerpc/rop-1.c
new file mode 100644
index 00000000000..8cedcb6668a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify that ROP-protect instructions are inserted when a
+   call is present.  */
+
+extern void foo (void);
+
+int bar ()
+{
+  foo ();
+  return 5;
+}
+
+/* { dg-final { scan-assembler-times {\mhashst\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mhashchk\M} 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-2.c b/gcc/testsuite/gcc.target/powerpc/rop-2.c
new file mode 100644
index 00000000000..c556952aec1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-2.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect -mprivileged" } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify that privileged ROP-protect instructions are inserted when a
+   call is present.  */
+
+extern void foo (void);
+
+int bar ()
+{
+  foo ();
+  return 5;
+}
+
+/* { dg-final { scan-assembler-times {\mhashstp\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mhashchkp\M} 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-3.c b/gcc/testsuite/gcc.target/powerpc/rop-3.c
new file mode 100644
index 00000000000..8d03792e3e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-3.c
@@ -0,0 +1,18 @@
+/* { dg-do run { target { power10_hw } } } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+
+/* Verify that ROP-protect instructions execute correctly when a
+   call is present.  */
+
+void __attribute__((noipa)) foo ()
+{
+  asm ("");
+}
+
+int main ()
+{
+  foo ();
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-4.c b/gcc/testsuite/gcc.target/powerpc/rop-4.c
new file mode 100644
index 00000000000..dcf47c63fb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-4.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify that no ROP-protect instructions are inserted when no
+   call is present.  */
+
+
+int bar ()
+{
+  return 5;
+}
+
+/* { dg-final { scan-assembler-not {\mhashst\M} } } */
+/* { dg-final { scan-assembler-not {\mhashchk\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/rop-5.c b/gcc/testsuite/gcc.target/powerpc/rop-5.c
new file mode 100644
index 00000000000..cf04ea90eeb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/rop-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */
+
+/* Verify that __ROP_PROTECT__ is predefined for -mrop-protect.  */
+
+int foo ()
+{
+#ifndef __ROP_PROTECT__
+  __ROP_PROTECT__ macro is not defined when it should be
+#endif
+  return 0;
+}
+
-- 
2.27.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags
  2021-05-14  3:34 ` [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
@ 2021-05-14 15:55   ` Segher Boessenkool
  2021-05-15 19:06     ` Bill Schmidt
  1 sibling, 1 reply; 16+ messages in thread
From: Segher Boessenkool @ 2021-05-14 15:55 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: gcc-patches, dje.gcc

On Thu, May 13, 2021 at 10:34:54PM -0500, Bill Schmidt via Gcc-patches wrote:
> +mprivileged
> +Target Var(rs6000_privileged) Init(0)
> +Enable generation of instructions that require privileged state.

That isn't quite it -- it will generate "p" insns instead of the usual
ones, it isn't just that it is allowed to generate the "p" insns.

> +@item -mprivileged
> +@itemx -mno-privileged
> +@opindex mprivileged
> +@opindex mno-privileged
> +Generate (do not generate) instructions for privileged state.

That is better.  But may I suggest:

"Generate code that will run in privileged state."

Okay for trunk and 11 with whatever you end up with.  Thanks!


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue
  2021-05-14  3:34 ` [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
@ 2021-05-14 18:44   ` Segher Boessenkool
  2021-05-14 19:10     ` Bill Schmidt
  1 sibling, 1 reply; 16+ messages in thread
From: Segher Boessenkool @ 2021-05-14 18:44 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: gcc-patches, dje.gcc

Hi!

On Thu, May 13, 2021 at 10:34:55PM -0500, Bill Schmidt via Gcc-patches wrote:
> +;; ROP mitigation instructions.
> +
> +(define_insn "hashst"
> +  [(set (match_operand:DI 0 "simple_offsettable_mem_operand" "=m")
> +        (unspec:DI [(match_operand:DI 1 "int_reg_operand" "r")]
> +	           UNSPEC_HASHST))]
> +  "TARGET_POWER10 && rs6000_rop_protect"
> +{
> +  static char templ[14];

14 is okay, but why not use 200 or so?  You don't call anything anyway
(except that sprintf itself perhaps).  Or 50 or whatever.  Something so
ridiculously big that you do not have to count, that's my point :-)

> +  char p[2];
> +
> +  if (rs6000_privileged)
> +    {
> +      p[0] = 'p';
> +      p[1] = 0;
> +    }
> +  else
> +    p[0] = 0;

const char *p = rs6000_privileged ? "p" : "";

Please make this an unspec_volatile?

> +(define_insn "hashchk"

Same things here of course, but it is volatile already.

Okay for trunk and 11 with such changes.  Thanks!


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__
  2021-05-14  3:34 ` [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__ Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
@ 2021-05-14 18:51   ` Segher Boessenkool
  1 sibling, 0 replies; 16+ messages in thread
From: Segher Boessenkool @ 2021-05-14 18:51 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: gcc-patches, dje.gcc

On Thu, May 13, 2021 at 10:34:56PM -0500, Bill Schmidt via Gcc-patches wrote:
> gcc/
> 	* config/rs6000/rs6000-c.c (rs6000_target_modify_macros): Define
> 	__ROP_PROTECT__ if -mrop-protect is selected.

Okay for trunk and 11.


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue
  2021-05-14 18:44   ` Segher Boessenkool
@ 2021-05-14 19:10     ` Bill Schmidt
  0 siblings, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-14 19:10 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches, dje.gcc

On 5/14/21 1:44 PM, Segher Boessenkool wrote:
> Please make this an unspec_volatile? 

Oops!  Sorry for missing that the first time.

Thanks for the review!!

Bill


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/4] rs6000: Add ROP tests
  2021-05-14  3:34 ` [PATCH 4/4] rs6000: Add ROP tests Bill Schmidt
  2021-05-14 14:18   ` Bill Schmidt
@ 2021-05-14 19:36   ` Segher Boessenkool
  1 sibling, 0 replies; 16+ messages in thread
From: Segher Boessenkool @ 2021-05-14 19:36 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: gcc-patches, dje.gcc

On Thu, May 13, 2021 at 10:34:57PM -0500, Bill Schmidt via Gcc-patches wrote:
> gcc/testsuite/
> 	* gcc.target/powerpc/rop-1.c: New.
> 	* gcc.target/powerpc/rop-2.c: New.
> 	* gcc.target/powerpc/rop-3.c: New.
> 	* gcc.target/powerpc/rop-4.c: New.
> 	* gcc.target/powerpc/rop-5.c: New.

Okay for trunk and everything.  Thanks!


Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags
  2021-05-14 15:55   ` Segher Boessenkool
@ 2021-05-15 19:06     ` Bill Schmidt
  0 siblings, 0 replies; 16+ messages in thread
From: Bill Schmidt @ 2021-05-15 19:06 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches, dje.gcc

Series pushed with recommended changes.  Thank you!

Bill

On 5/14/21 10:55 AM, Segher Boessenkool wrote:
> On Thu, May 13, 2021 at 10:34:54PM -0500, Bill Schmidt via Gcc-patches wrote:
>> +mprivileged
>> +Target Var(rs6000_privileged) Init(0)
>> +Enable generation of instructions that require privileged state.
> That isn't quite it -- it will generate "p" insns instead of the usual
> ones, it isn't just that it is allowed to generate the "p" insns.
>
>> +@item -mprivileged
>> +@itemx -mno-privileged
>> +@opindex mprivileged
>> +@opindex mno-privileged
>> +Generate (do not generate) instructions for privileged state.
> That is better.  But may I suggest:
>
> "Generate code that will run in privileged state."
>
> Okay for trunk and 11 with whatever you end up with.  Thanks!
>
>
> Segher

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-05-15 19:06 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-14  3:34 [PATCHv2 0/4] ROP support Bill Schmidt
2021-05-14  3:34 ` [PATCH 1/4] rs6000: Add -mrop-protect and -mprivileged flags Bill Schmidt
2021-05-14 14:18   ` Bill Schmidt
2021-05-14 15:55   ` Segher Boessenkool
2021-05-15 19:06     ` Bill Schmidt
2021-05-14  3:34 ` [PATCH 2/4] rs6000: Emit ROP-mitigation instructions in prologue and epilogue Bill Schmidt
2021-05-14 14:18   ` Bill Schmidt
2021-05-14 18:44   ` Segher Boessenkool
2021-05-14 19:10     ` Bill Schmidt
2021-05-14  3:34 ` [PATCH 3/4] rs6000: Conditionally define __ROP_PROTECT__ Bill Schmidt
2021-05-14 14:18   ` Bill Schmidt
2021-05-14 18:51   ` Segher Boessenkool
2021-05-14  3:34 ` [PATCH 4/4] rs6000: Add ROP tests Bill Schmidt
2021-05-14 14:18   ` Bill Schmidt
2021-05-14 19:36   ` Segher Boessenkool
2021-05-14 14:18 ` [PATCHv2 0/4] ROP support Bill Schmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).