Hi Szabolcs,

> -----Original Message-----
> From: Szabolcs Nagy <szabolcs.n...@arm.com>
> Sent: 09 April 2020 15:20
> To: gcc-patches@gcc.gnu.org
> Cc: Richard Earnshaw <richard.earns...@arm.com>; Richard Sandiford
> <richard.sandif...@arm.com>; Kyrylo Tkachov <kyrylo.tkac...@arm.com>
> Subject: [PATCH] aarch64, libgcc: Fix unwinding from pac-ret to normal
> frames [PR94514]
> 
> With -mbranch-protection=pac-ret the debug info toggles the
> signedness state of the return address so the unwinder knows when
> the return address needs pointer authentication.
> 
> The unwind context flags were not updated according to the dwarf
> frame info.
> 
> This causes unwinding across frames that were built without pac-ret
> to incorrectly authenticate the return address wich corrupts the
> return address on a system where PAuth is enabled.
> 
> Note: This even affects systems where all code use pac-ret because
> unwinding across a signal frame the return address is not signed.
> 

Ok, I'm guessing this needs backporting?
Thanks,
Kyrill

> gcc/testsuite/ChangeLog:
> 
> 2020-04-XX  Szabolcs Nagy  <szabolcs.n...@arm.com>
> 
>       PR target/94514
>       * g++.target/aarch64/pr94514.C: New test.
>       * gcc.target/aarch64/pr94514.c: New test.
> 
> libgcc/ChangeLog:
> 
> 2020-04-XX  Szabolcs Nagy  <szabolcs.n...@arm.com>
> 
>       PR target/94514
>       * config/aarch64/aarch64-unwind.h (aarch64_frob_update_context):
>       Update context->flags accroding to the frame state.
> ---
>  gcc/testsuite/g++.target/aarch64/pr94514.C | 26 ++++++++
>  gcc/testsuite/gcc.target/aarch64/pr94514.c | 76 ++++++++++++++++++++++
>  libgcc/config/aarch64/aarch64-unwind.h     |  2 +
>  3 files changed, 104 insertions(+)
>  create mode 100644 gcc/testsuite/g++.target/aarch64/pr94514.C
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/pr94514.c
> 
> diff --git a/gcc/testsuite/g++.target/aarch64/pr94514.C
> b/gcc/testsuite/g++.target/aarch64/pr94514.C
> new file mode 100644
> index 00000000000..2a8c949ba30
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/aarch64/pr94514.C
> @@ -0,0 +1,26 @@
> +/* PR target/94514. Unwind across mixed pac-ret and non-pac-ret frames.
> */
> +/* { dg-do run } */
> +
> +__attribute__((noinline, target("branch-protection=pac-ret")))
> +static void do_throw (void)
> +{
> +  throw 42;
> +  __builtin_abort ();
> +}
> +
> +__attribute__((noinline, target("branch-protection=none")))
> +static void no_pac_ret (void)
> +{
> +  do_throw ();
> +  __builtin_abort ();
> +}
> +
> +int main ()
> +{
> +  try {
> +    no_pac_ret ();
> +  } catch (...) {
> +    return 0;
> +  }
> +  __builtin_abort ();
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/pr94514.c
> b/gcc/testsuite/gcc.target/aarch64/pr94514.c
> new file mode 100644
> index 00000000000..bbbf5a6b0b3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/pr94514.c
> @@ -0,0 +1,76 @@
> +/* PR target/94514. Unwind across mixed pac-ret and non-pac-ret frames.
> */
> +/* { dg-do run } */
> +/* { dg-options "-fexceptions -O2" } */
> +
> +#include <unwind.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#define die() \
> +  do { \
> +    printf ("%s:%d: reached unexpectedly.\n", __FILE__, __LINE__); \
> +    fflush (stdout); \
> +    abort (); \
> +  } while (0)
> +
> +static struct _Unwind_Exception exc;
> +
> +static _Unwind_Reason_Code
> +force_unwind_stop (int version, _Unwind_Action actions,
> +                   _Unwind_Exception_Class exc_class,
> +                   struct _Unwind_Exception *exc_obj,
> +                   struct _Unwind_Context *context,
> +                   void *stop_parameter)
> +{
> +  printf ("%s: CFA: %p PC: %p actions: %d\n",
> +       __func__,
> +       (void *)_Unwind_GetCFA (context),
> +       (void *)_Unwind_GetIP (context),
> +       (int)actions);
> +  if (actions & _UA_END_OF_STACK)
> +    die ();
> +  return _URC_NO_REASON;
> +}
> +
> +static void force_unwind (void)
> +{
> +#ifndef __USING_SJLJ_EXCEPTIONS__
> +  _Unwind_ForcedUnwind (&exc, force_unwind_stop, 0);
> +#else
> +  _Unwind_SjLj_ForcedUnwind (&exc, force_unwind_stop, 0);
> +#endif
> +}
> +
> +__attribute__((noinline, target("branch-protection=pac-ret")))
> +static void f2_pac_ret (void)
> +{
> +  force_unwind ();
> +  die ();
> +}
> +
> +__attribute__((noinline, target("branch-protection=none")))
> +static void f1_no_pac_ret (void)
> +{
> +  f2_pac_ret ();
> +  die ();
> +}
> +
> +__attribute__((noinline, target("branch-protection=pac-ret")))
> +static void f0_pac_ret (void)
> +{
> +  f1_no_pac_ret ();
> +  die ();
> +}
> +
> +static void cleanup_handler (void *p)
> +{
> +  printf ("%s: Success.\n", __func__);
> +  exit (0);
> +}
> +
> +int main ()
> +{
> +  char dummy __attribute__((cleanup (cleanup_handler)));
> +  f0_pac_ret ();
> +  die ();
> +}
> diff --git a/libgcc/config/aarch64/aarch64-unwind.h
> b/libgcc/config/aarch64/aarch64-unwind.h
> index 4c8790bae67..ed84a96db41 100644
> --- a/libgcc/config/aarch64/aarch64-unwind.h
> +++ b/libgcc/config/aarch64/aarch64-unwind.h
> @@ -104,6 +104,8 @@ aarch64_frob_update_context (struct
> _Unwind_Context *context,
>    if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
>      /* The flag is used for re-authenticating EH handler's address.  */
>      context->flags |= RA_SIGNED_BIT;
> +  else
> +    context->flags &= ~RA_SIGNED_BIT;
> 
>    return;
>  }
> --
> 2.17.1

Reply via email to