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