gcc7/gcc7-aarch64-sls-miti-2.patch

607 lines
20 KiB
Diff
Raw Normal View History

Backport of below commit for bsc#1172798
Also adds the AARCH64_FL_SB support, not originally part of
this commit. And the added test sls-miti-retbr.c has -mbranch-protection
removed as that's not supported by our gcc7.
commit dc586a749228ecfb71f72ec2ca10e6f7b6874af3
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date: Thu Jul 9 09:11:59 2020 +0100
aarch64: Introduce SLS mitigation for RET and BR instructions
Instructions following RET or BR are not necessarily executed. In order
to avoid speculation past RET and BR we can simply append a speculation
barrier.
Since these speculation barriers will not be architecturally executed,
they are not expected to add a high performance penalty.
The speculation barrier is to be SB when targeting architectures which
have this enabled, and DSB SY + ISB otherwise.
We add tests for each of the cases where such an instruction was seen.
This is implemented by modifying each machine description pattern that
emits either a RET or a BR instruction. We choose not to use something
like `TARGET_ASM_FUNCTION_EPILOGUE` since it does not affect the
`indirect_jump`, `jump`, `sibcall_insn` and `sibcall_value_insn`
patterns and we find it preferable to implement the functionality in the
same way for every pattern.
There is one particular case which is slightly tricky. The
implementation of TARGET_ASM_TRAMPOLINE_TEMPLATE uses a BR which needs
to be mitigated against. The trampoline template is used *once* per
compilation unit, and the TRAMPOLINE_SIZE is exposed to the user via the
builtin macro __LIBGCC_TRAMPOLINE_SIZE__.
In the future we may implement function specific attributes to turn on
and off hardening on a per-function basis.
The fixed nature of the trampoline described above implies it will be
safer to ensure this speculation barrier is always used.
Testing:
Bootstrap and regtest done on aarch64-none-linux
Used a temporary hack(1) to use these options on every test in the
testsuite and a script to check that the output never emitted an
unmitigated RET or BR.
1) Temporary hack was a change to the testsuite to always use
`-save-temps` and run a script on the assembly output of those
compilations which produced one to ensure every RET or BR is immediately
followed by a speculation barrier.
(cherry picked from be178ecd5ac1fe1510d960ff95c66d0ff831afe1)
gcc/ChangeLog:
* config/aarch64/aarch64-protos.h (aarch64_sls_barrier): New.
* config/aarch64/aarch64.c (aarch64_output_casesi): Emit
speculation barrier after BR instruction if needs be.
(aarch64_trampoline_init): Handle ptr_mode value & adjust size
of code copied.
(aarch64_sls_barrier): New.
(aarch64_asm_trampoline_template): Add needed barriers.
* config/aarch64/aarch64.h (AARCH64_ISA_SB): New.
(TARGET_SB): New.
(TRAMPOLINE_SIZE): Account for barrier.
* config/aarch64/aarch64.md (indirect_jump, *casesi_dispatch,
simple_return, *do_return, *sibcall_insn, *sibcall_value_insn):
Emit barrier if needs be, also account for possible barrier using
"sls_length" attribute.
(sls_length): New attribute.
(length): Determine default using any non-default sls_length
value.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c: New test.
* gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c:
New test.
* gcc.target/aarch64/sls-mitigation/sls-mitigation.exp: New file.
* lib/target-supports.exp (check_effective_target_aarch64_asm_sb_ok):
New proc.
Index: gcc-7.5.0+r278197/gcc/config/aarch64/aarch64-protos.h
===================================================================
--- gcc-7.5.0+r278197.orig/gcc/config/aarch64/aarch64-protos.h
+++ gcc-7.5.0+r278197/gcc/config/aarch64/aarch64-protos.h
@@ -485,6 +485,7 @@ extern const atomic_ool_names aarch64_oo
extern const atomic_ool_names aarch64_ool_ldclr_names;
extern const atomic_ool_names aarch64_ool_ldeor_names;
+const char *aarch64_sls_barrier (int);
extern bool aarch64_harden_sls_retbr_p (void);
extern bool aarch64_harden_sls_blr_p (void);
Index: gcc-7.5.0+r278197/gcc/config/aarch64/aarch64.c
===================================================================
--- gcc-7.5.0+r278197.orig/gcc/config/aarch64/aarch64.c
+++ gcc-7.5.0+r278197/gcc/config/aarch64/aarch64.c
@@ -5736,15 +5736,28 @@ aarch64_asm_trampoline_template (FILE *f
{
if (TARGET_ILP32)
{
- asm_fprintf (f, "\tldr\tw%d, .+16\n", IP1_REGNUM - R0_REGNUM);
- asm_fprintf (f, "\tldr\tw%d, .+16\n", STATIC_CHAIN_REGNUM - R0_REGNUM);
+ asm_fprintf (f, "\tldr\tw%d, .+24\n", IP1_REGNUM - R0_REGNUM);
+ asm_fprintf (f, "\tldr\tw%d, .+24\n", STATIC_CHAIN_REGNUM - R0_REGNUM);
}
else
{
- asm_fprintf (f, "\tldr\t%s, .+16\n", reg_names [IP1_REGNUM]);
- asm_fprintf (f, "\tldr\t%s, .+20\n", reg_names [STATIC_CHAIN_REGNUM]);
+ asm_fprintf (f, "\tldr\t%s, .+24\n", reg_names [IP1_REGNUM]);
+ asm_fprintf (f, "\tldr\t%s, .+28\n", reg_names [STATIC_CHAIN_REGNUM]);
}
asm_fprintf (f, "\tbr\t%s\n", reg_names [IP1_REGNUM]);
+
+ /* We always emit a speculation barrier.
+ This is because the same trampoline template is used for every nested
+ function. Since nested functions are not particularly common or
+ performant we don't worry too much about the extra instructions to copy
+ around.
+ This is not yet a problem, since we have not yet implemented function
+ specific attributes to choose between hardening against straight line
+ speculation or not, but such function specific attributes are likely to
+ happen in the future. */
+ asm_fprintf (f, "\tdsb\tsy\n\tisb\n");
+
+ /* Padding for BTI at the beginning, which our gcc-7 backports don't do */
assemble_aligned_integer (4, const0_rtx);
assemble_aligned_integer (POINTER_BYTES, const0_rtx);
assemble_aligned_integer (POINTER_BYTES, const0_rtx);
@@ -5754,10 +5767,14 @@ static void
aarch64_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
{
rtx fnaddr, mem, a_tramp;
- const int tramp_code_sz = 16;
+ const int tramp_code_sz = 24;
/* Don't need to copy the trailing D-words, we fill those in below. */
- emit_block_move (m_tramp, assemble_trampoline_template (),
+ /* We create our own memory address in Pmode so that `emit_block_move` can
+ use parts of the backend which expect Pmode addresses. */
+ rtx temp = convert_memory_address (Pmode, XEXP (m_tramp, 0));
+ emit_block_move (gen_rtx_MEM (BLKmode, temp),
+ assemble_trampoline_template (),
GEN_INT (tramp_code_sz), BLOCK_OP_NORMAL);
mem = adjust_address (m_tramp, ptr_mode, tramp_code_sz);
fnaddr = XEXP (DECL_RTL (fndecl), 0);
@@ -5936,6 +5953,8 @@ aarch64_output_casesi (rtx *operands)
output_asm_insn (buf, operands);
output_asm_insn (patterns[index][1], operands);
output_asm_insn ("br\t%3", operands);
+ output_asm_insn (aarch64_sls_barrier (aarch64_harden_sls_retbr_p ()),
+ operands);
assemble_label (asm_out_file, label);
return "";
}
@@ -14664,6 +14683,22 @@ aarch64_sched_can_speculate_insn (rtx_in
}
}
+/* Helper function for straight line speculation.
+ Return what barrier should be emitted for straight line speculation
+ mitigation.
+ When not mitigating against straight line speculation this function returns
+ an empty string.
+ When mitigating against straight line speculation, use:
+ * SB when the v8.5-A SB extension is enabled.
+ * DSB+ISB otherwise. */
+const char *
+aarch64_sls_barrier (int mitigation_required)
+{
+ return mitigation_required
+ ? (TARGET_SB ? "sb" : "dsb\tsy\n\tisb")
+ : "";
+}
+
/* Target-specific selftests. */
#if CHECKING_P
Index: gcc-7.5.0+r278197/gcc/config/aarch64/aarch64.h
===================================================================
--- gcc-7.5.0+r278197.orig/gcc/config/aarch64/aarch64.h
+++ gcc-7.5.0+r278197/gcc/config/aarch64/aarch64.h
@@ -141,6 +141,9 @@ extern unsigned aarch64_architecture_ver
/* ARMv8.3-A architecture extensions. */
#define AARCH64_FL_V8_3 (1 << 10) /* Has ARMv8.3-A features. */
+/* Speculation Barrier instruction supported. */
+#define AARCH64_FL_SB (1 << 25)
+
/* Has FP and SIMD. */
#define AARCH64_FL_FPSIMD (AARCH64_FL_FP | AARCH64_FL_SIMD)
@@ -168,6 +171,8 @@ extern unsigned aarch64_architecture_ver
#define AARCH64_ISA_F16 (aarch64_isa_flags & AARCH64_FL_F16)
#define AARCH64_ISA_V8_3 (aarch64_isa_flags & AARCH64_FL_V8_3)
+#define AARCH64_ISA_SB (aarch64_isa_flags & AARCH64_FL_SB)
+
/* Crypto is an optional extension to AdvSIMD. */
#define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
@@ -193,6 +198,9 @@ extern unsigned aarch64_architecture_ver
#define TARGET_FIX_ERR_A53_835769_DEFAULT 1
#endif
+/* SB instruction is enabled through +sb. */
+#define TARGET_SB (AARCH64_ISA_SB)
+
/* Apply the workaround for Cortex-A53 erratum 835769. */
#define TARGET_FIX_ERR_A53_835769 \
((aarch64_fix_a53_err835769 == 2) \
@@ -805,8 +813,10 @@ typedef struct
#define RETURN_ADDR_RTX aarch64_return_addr
-/* 3 insns + padding + 2 pointer-sized entries. */
-#define TRAMPOLINE_SIZE (TARGET_ILP32 ? 24 : 32)
+/* BTI c + 3 insns
+ + sls barrier of DSB + ISB.
+ + 2 pointer-sized entries. */
+#define TRAMPOLINE_SIZE (24 + (TARGET_ILP32 ? 8 : 16))
/* Trampolines contain dwords, so must be dword aligned. */
#define TRAMPOLINE_ALIGNMENT 64
Index: gcc-7.5.0+r278197/gcc/config/aarch64/aarch64.md
===================================================================
--- gcc-7.5.0+r278197.orig/gcc/config/aarch64/aarch64.md
+++ gcc-7.5.0+r278197/gcc/config/aarch64/aarch64.md
@@ -187,8 +187,23 @@
;; will be disabled when !TARGET_SIMD.
(define_attr "simd" "no,yes" (const_string "no"))
+;; Attribute to specify that an alternative has the length of a single
+;; instruction plus a speculation barrier.
+(define_attr "sls_length" "none,retbr,casesi" (const_string "none"))
+
(define_attr "length" ""
- (const_int 4))
+ (cond [
+ (eq_attr "sls_length" "retbr")
+ (cond [(match_test "!aarch64_harden_sls_retbr_p ()") (const_int 4)
+ (match_test "TARGET_SB") (const_int 8)]
+ (const_int 12))
+
+ (eq_attr "sls_length" "casesi")
+ (cond [(match_test "!aarch64_harden_sls_retbr_p ()") (const_int 16)
+ (match_test "TARGET_SB") (const_int 20)]
+ (const_int 24))
+ ]
+ (const_int 4)))
;; Attribute that controls whether an alternative is enabled or not.
;; Currently it is only used to disable alternatives which touch fp or simd
@@ -235,8 +250,12 @@
(define_insn "indirect_jump"
[(set (pc) (match_operand:DI 0 "register_operand" "r"))]
""
- "br\\t%0"
- [(set_attr "type" "branch")]
+ {
+ output_asm_insn ("br\\t%0", operands);
+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+ }
+ [(set_attr "type" "branch")
+ (set_attr "sls_length" "retbr")]
)
(define_insn "jump"
@@ -508,7 +527,7 @@
"*
return aarch64_output_casesi (operands);
"
- [(set_attr "length" "16")
+ [(set_attr "sls_length" "casesi")
(set_attr "type" "branch")]
)
@@ -583,14 +602,18 @@
[(return)]
""
{
+ const char *ret = NULL;
if (aarch64_return_address_signing_enabled ()
&& TARGET_ARMV8_3
&& !crtl->calls_eh_return)
- return "retaa";
-
- return "ret";
+ ret = "retaa";
+ else
+ ret = "ret";
+ output_asm_insn (ret, operands);
+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
}
- [(set_attr "type" "branch")]
+ [(set_attr "type" "branch")
+ (set_attr "sls_length" "retbr")]
)
(define_expand "return"
@@ -602,8 +625,12 @@
(define_insn "simple_return"
[(simple_return)]
""
- "ret"
- [(set_attr "type" "branch")]
+ {
+ output_asm_insn ("ret", operands);
+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+ }
+ [(set_attr "type" "branch")
+ (set_attr "sls_length" "retbr")]
)
(define_insn "*cb<optab><mode>1"
@@ -903,10 +930,16 @@
(return)
(use (match_operand 2 "" ""))]
"SIBLING_CALL_P (insn)"
- "@
- br\\t%0
- b\\t%a0"
- [(set_attr "type" "branch, branch")]
+ {
+ if (which_alternative == 0)
+ {
+ output_asm_insn ("br\\t%0", operands);
+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+ }
+ return "b\\t%c0";
+ }
+ [(set_attr "type" "branch, branch")
+ (set_attr "sls_length" "retbr,none")]
)
(define_insn "*sibcall_value_insn"
@@ -917,10 +950,16 @@
(return)
(use (match_operand 3 "" ""))]
"SIBLING_CALL_P (insn)"
- "@
- br\\t%1
- b\\t%a1"
- [(set_attr "type" "branch, branch")]
+ {
+ if (which_alternative == 0)
+ {
+ output_asm_insn ("br\\t%1", operands);
+ return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+ }
+ return "b\\t%c1";
+ }
+ [(set_attr "type" "branch, branch")
+ (set_attr "sls_length" "retbr,none")]
)
;; Call subroutine returning any type.
Index: gcc-7.5.0+r278197/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c
===================================================================
--- /dev/null
+++ gcc-7.5.0+r278197/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr-pacret.c
@@ -0,0 +1,15 @@
+/* Avoid ILP32 since pacret is only available for LP64 */
+/* { dg-do compile { target { ! ilp32 } } } */
+/* { dg-additional-options "-mharden-sls=retbr -march=armv8.3-a" } */
+
+/* Testing the do_return pattern for retaa. */
+long retbr_subcall(void);
+long retbr_do_return_retaa(void)
+{
+ return retbr_subcall()+1;
+}
+
+/* Ensure there are no BR or RET instructions which are not directly followed
+ by a speculation barrier. */
+/* { dg-final { scan-assembler-not {\t(br|ret|retaa)\tx[0-9][0-9]?\n\t(?!dsb\tsy\n\tisb)} } } */
+/* { dg-final { scan-assembler-not {ret\t} } } */
Index: gcc-7.5.0+r278197/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c
===================================================================
--- /dev/null
+++ gcc-7.5.0+r278197/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-miti-retbr.c
@@ -0,0 +1,119 @@
+/* We ensure that -Wpedantic is off since it complains about the trampolines
+ we explicitly want to test. */
+/* { dg-additional-options "-mharden-sls=retbr -Wno-pedantic " } */
+/*
+ Ensure that the SLS hardening of RET and BR leaves no unprotected RET/BR
+ instructions.
+ */
+typedef int (foo) (int, int);
+typedef void (bar) (int, int);
+struct sls_testclass {
+ foo *x;
+ bar *y;
+ int left;
+ int right;
+};
+
+int
+retbr_sibcall_value_insn (struct sls_testclass x)
+{
+ return x.x(x.left, x.right);
+}
+
+void
+retbr_sibcall_insn (struct sls_testclass x)
+{
+ x.y(x.left, x.right);
+}
+
+/* Aim to test two different returns.
+ One that introduces a tail call in the middle of the function, and one that
+ has a normal return. */
+int
+retbr_multiple_returns (struct sls_testclass x)
+{
+ int temp;
+ if (x.left % 10)
+ return x.x(x.left, 100);
+ else if (x.right % 20)
+ {
+ return x.x(x.left * x.right, 100);
+ }
+ temp = x.left % x.right;
+ temp *= 100;
+ temp /= 2;
+ return temp % 3;
+}
+
+void
+retbr_multiple_returns_void (struct sls_testclass x)
+{
+ if (x.left % 10)
+ {
+ x.y(x.left, 100);
+ }
+ else if (x.right % 20)
+ {
+ x.y(x.left * x.right, 100);
+ }
+ return;
+}
+
+/* Testing the casesi jump via register. */
+__attribute__ ((optimize ("Os")))
+int
+retbr_casesi_dispatch (struct sls_testclass x)
+{
+ switch (x.left)
+ {
+ case -5:
+ return -2;
+ case -3:
+ return -1;
+ case 0:
+ return 0;
+ case 3:
+ return 1;
+ case 5:
+ break;
+ default:
+ __builtin_unreachable ();
+ }
+ return x.right;
+}
+
+/* Testing the BR in trampolines is mitigated against. */
+void f1 (void *);
+void f3 (void *, void (*)(void *));
+void f2 (void *);
+
+int
+retbr_trampolines (void *a, int b)
+{
+ if (!b)
+ {
+ f1 (a);
+ return 1;
+ }
+ if (b)
+ {
+ void retbr_tramp_internal (void *c)
+ {
+ if (c == a)
+ f2 (c);
+ }
+ f3 (a, retbr_tramp_internal);
+ }
+ return 0;
+}
+
+/* Testing the indirect_jump pattern. */
+void
+retbr_indirect_jump (int *buf)
+{
+ __builtin_longjmp(buf, 1);
+}
+
+/* Ensure there are no BR or RET instructions which are not directly followed
+ by a speculation barrier. */
+/* { dg-final { scan-assembler-not {\t(br|ret|retaa)\tx[0-9][0-9]?\n\t(?!dsb\tsy\n\tisb|sb)} } } */
Index: gcc-7.5.0+r278197/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-mitigation.exp
===================================================================
--- /dev/null
+++ gcc-7.5.0+r278197/gcc/testsuite/gcc.target/aarch64/sls-mitigation/sls-mitigation.exp
@@ -0,0 +1,73 @@
+# Regression driver for SLS mitigation on AArch64.
+# Copyright (C) 2020 Free Software Foundation, Inc.
+# Contributed by ARM Ltd.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>. */
+
+# Exit immediately if this isn't an AArch64 target.
+if {![istarget aarch64*-*-*] } then {
+ return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+load_lib torture-options.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " "
+}
+
+# Initialize `dg'.
+dg-init
+torture-init
+
+# Use different architectures as well as the normal optimisation options.
+# (i.e. use both SB and DSB+ISB barriers).
+
+set save-dg-do-what-default ${dg-do-what-default}
+# Main loop.
+# Run with torture tests (i.e. a bunch of different optimisation levels) just
+# to increase test coverage.
+set dg-do-what-default assemble
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+ "-save-temps" $DEFAULT_CFLAGS
+
+# Run the same tests but this time with SB extension.
+# Since not all supported assemblers will support that extension we decide
+# whether to assemble or just compile based on whether the extension is
+# supported for the available assembler.
+
+set templist {}
+foreach x $DG_TORTURE_OPTIONS {
+ lappend templist "$x -march=armv8.3-a+sb "
+ lappend templist "$x -march=armv8-a+sb "
+}
+set-torture-options $templist
+if { [check_effective_target_aarch64_asm_sb_ok] } {
+ set dg-do-what-default assemble
+} else {
+ set dg-do-what-default compile
+}
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+ "-save-temps" $DEFAULT_CFLAGS
+set dg-do-what-default ${save-dg-do-what-default}
+
+# All done.
+torture-finish
+dg-finish
Index: gcc-7.5.0+r278197/gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc-7.5.0+r278197.orig/gcc/testsuite/lib/target-supports.exp
+++ gcc-7.5.0+r278197/gcc/testsuite/lib/target-supports.exp
@@ -7929,7 +7929,7 @@ proc check_effective_target_aarch64_tiny
# Create functions to check that the AArch64 assembler supports the
# various architecture extensions via the .arch_extension pseudo-op.
-foreach { aarch64_ext } { "fp" "simd" "crypto" "crc" "lse"} {
+foreach { aarch64_ext } { "fp" "simd" "crypto" "crc" "lse" "sb"} {
eval [string map [list FUNC $aarch64_ext] {
proc check_effective_target_aarch64_asm_FUNC_ok { } {
if { [istarget aarch64*-*-*] } {
Index: gcc-7.5.0+r278197/gcc/config/aarch64/aarch64-option-extensions.def
===================================================================
--- gcc-7.5.0+r278197.orig/gcc/config/aarch64/aarch64-option-extensions.def
+++ gcc-7.5.0+r278197/gcc/config/aarch64/aarch64-option-extensions.def
@@ -60,4 +60,7 @@ AARCH64_OPT_EXTENSION("lse", AARCH64_FL_
Disabling "fp16" just disables "fp16". */
AARCH64_OPT_EXTENSION("fp16", AARCH64_FL_F16, AARCH64_FL_FP, 0, "fphp asimdhp")
+/* Enabling/Disabling "sb" only changes "sb". */
+AARCH64_OPT_EXTENSION("sb", AARCH64_FL_SB, 0, 0, "sb")
+
#undef AARCH64_OPT_EXTENSION