[PATCH 0/6] Fix unwinding through sigreturn trampolines

Ard Biesheuvel ardb at kernel.org
Tue Jun 23 08:39:47 EDT 2020


On Tue, 23 Jun 2020 at 13:11, Szabolcs Nagy <szabolcs.nagy at arm.com> wrote:
>
> The 06/23/2020 12:11, Ard Biesheuvel wrote:
> > So the safest way to fix this (imho) is to add CFI directives that
> > mirror what libunwind does unconditionally, and libgcc when it spots
> > the mov/svc pair on unannotated addresses, which is to restore all the
> > registers from the sigframe, and to use regs->pc as the return address
> > (which is where the unwind should proceed, rather than at whatever
> > value happened to reside in x30 at the point the signal was taken)
> >
> > The only hairy bit is the FP/SIMD registers, which are ignored by
> > libunwind, and only half-restored by libgcc (which appears to assume
> > that only d8..d15 need to be restored). This means throwing a C++
> > exception in a signal handler and catching it outside of it is going
> > to be difficult to get 100% correct, but this is something that
> > appears to be broken already everywhere. (Unless there are some
> > AAPCS/ABI rules that specify that FP/SIMD registers have to be assumed
> > clobbered when catching an exception)
>
> all fp/simd registers are assumed to be clobbered after
> a function call, except for the bottom part of v8-v15
> (sve calls preserve more: v8-v23 which may be a problem)
>
> this means if the exception is caught at least one call
> frame above the interrupted function then the libgcc
> logic should work.
>
> if you want to catch exceptions at the same call frame
> that is interrupted by the signal, then you need to
> compile with -fnon-call-exceptions which has limitations
> anyway and not expected to be reliable (apparently on
> aarch64 libgcc does not even support this usage with
> respect to fp/simd regs, which is good to know..)
>
> this is all fine because c++ does not define exception
> handling across signal handlers.
>

It doesn't? In that case, all we need to take into account is cleanup
handlers, which are not permitted to catch exceptions.

I did notice that GCC permits cleanup handlers to be nested functions,
which means they could potentially attempt to access the outer
function's scope. Not sure what that means for unwinding, though.

> as for thread cancellation in glibc: it uses exception
> mechanism for cleanups, but the default cancel state
> is PTHREAD_CANCEL_DEFERRED which means only blocking
> libc calls throw (so -fexceptions is enough and the
> libgcc logic is fine), if you switch to
> PTHREAD_CANCEL_ASYNCHRONOUS then there may be a problem
> but you can only do pure computations in that state,
> (only 3 libc functions are defined to be async cancel
> safe), i think you cannot register cleanup handlers
> that run on the same stack frame that may be async
> interrupted.



More information about the linux-arm-kernel mailing list