[gcc(refs/vendors/ARM/heads/arm-perf-staging)] aarch64: fix __builtin_eh_return with pac-ret [PR94891]

Tamar Christina tnfchris@gcc.gnu.org
Fri Jul 17 15:42:00 GMT 2020


https://gcc.gnu.org/g:eb41624df3bfee5dd4183738f57e1cf54a2a32eb

commit eb41624df3bfee5dd4183738f57e1cf54a2a32eb
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Thu Jun 4 13:42:16 2020 +0100

    aarch64: fix __builtin_eh_return with pac-ret [PR94891]
    
    Currently __builtin_eh_return takes a signed return address, which can
    cause ABI and API issues: 1) pointer representation problems if the
    address is passed around before eh return, 2) the source code needs
    pac-ret specific changes and needs to know if pac-ret is used in the
    current frame, 3) signed address may not be representible as void *
    (with ilp32 abi).
    
    Using address signing to protect eh return is ineffective because the
    instruction sequence in the unwinder that starts from the address
    signing and ends with a ret can be used as a return to anywhere gadget.
    Using indirect branch istead of ret with bti j landing pads at the
    target can reduce the potential of such gadget, which also implies
    that __builtin_eh_return should not take a signed address.
    
    This is a big hammer fix to the ABI and API issues: it turns pac-ret
    off for the caller completely (not just on the eh return path).  To
    harden the caller against ROP attacks, it should use indirect branch
    instead of ret, this is not attempted so the patch remains small and
    backportable.
    
    2020-07-13  Szabolcs Nagy  <szabolcs.nagy@arm.com>
    
    gcc/ChangeLog:
    
            PR target/94891
            * config/aarch64/aarch64.c (aarch64_return_address_signing_enabled):
            Disable return address signing if __builtin_eh_return is used.
    
    gcc/testsuite/ChangeLog:
    
            PR target/94891
            * gcc.target/aarch64/return_address_sign_1.c: Update test.
            * gcc.target/aarch64/return_address_sign_b_1.c: Likewise.
    
    (cherry picked from commit 2bc95be3bb8c8138e2e87c1c11c84bfede989d61)

Diff:
---
 gcc/config/aarch64/aarch64.c                               | 11 +++++++++++
 gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c   |  8 ++++----
 gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c |  8 ++++----
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 1f285eead3c..c34f82dc283 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -6946,6 +6946,17 @@ aarch64_return_address_signing_enabled (void)
   /* This function should only be called after frame laid out.   */
   gcc_assert (cfun->machine->frame.laid_out);
 
+  /* Turn return address signing off in any function that uses
+     __builtin_eh_return.  The address passed to __builtin_eh_return
+     is not signed so either it has to be signed (with original sp)
+     or the code path that uses it has to avoid authenticating it.
+     Currently eh return introduces a return to anywhere gadget, no
+     matter what we do here since it uses ret with user provided
+     address. An ideal fix for that is to use indirect branch which
+     can be protected with BTI j (to some extent).  */
+  if (crtl->calls_eh_return)
+    return false;
+
   /* If signing scope is AARCH64_FUNCTION_NON_LEAF, we only sign a leaf function
      if its LR is pushed onto stack.  */
   return (aarch64_ra_sign_scope == AARCH64_FUNCTION_ALL
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
index 0140bee194f..232ba67ade0 100644
--- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c
@@ -41,12 +41,12 @@ func3 (int a, int b, int c)
 void __attribute__ ((target ("arch=armv8.3-a")))
 func4 (long offset, void *handler, int *ptr, int imm1, int imm2)
 {
-  /* paciasp */
+  /* no paciasp */
   *ptr = imm1 + foo (imm1) + imm2;
   __builtin_eh_return (offset, handler);
-  /* autiasp */
+  /* no autiasp */
   return;
 }
 
-/* { dg-final { scan-assembler-times "autiasp" 4 } } */
-/* { dg-final { scan-assembler-times "paciasp" 4 } } */
+/* { dg-final { scan-assembler-times "autiasp" 3 } } */
+/* { dg-final { scan-assembler-times "paciasp" 3 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c
index 32d788ddf3f..43e32ab6cb7 100644
--- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c
@@ -41,12 +41,12 @@ func3 (int a, int b, int c)
 void __attribute__ ((target ("arch=armv8.3-a")))
 func4 (long offset, void *handler, int *ptr, int imm1, int imm2)
 {
-  /* pacibsp */
+  /* no pacibsp */
   *ptr = imm1 + foo (imm1) + imm2;
   __builtin_eh_return (offset, handler);
-  /* autibsp */
+  /* no autibsp */
   return;
 }
 
-/* { dg-final { scan-assembler-times "pacibsp" 4 } } */
-/* { dg-final { scan-assembler-times "autibsp" 4 } } */
+/* { dg-final { scan-assembler-times "pacibsp" 3 } } */
+/* { dg-final { scan-assembler-times "autibsp" 3 } } */


More information about the Gcc-cvs mailing list