[PATCH v2] powerpc64: Workaround sigtramp vdso return call

Adhemerval Zanella adhemerval.zanella@linaro.org
Wed Jan 27 19:33:09 GMT 2021



On 27/01/2021 16:23, Raoni Fassina Firmino wrote:
> Changes since v1[1]:
>   - Fixed comments length and formatting;
>   - Changed comment wording to the one suggested by Adhermeval;
>   - Changed if logic to the one suggested by Adhermeval.
> 
> Original message:
>   There was some initial discussions on the mailing list about the
>   failing misc/tst-sigcontext-get_pc[0], and I made some suggestions
>   of possible solutions.  As the window for the release is closing I
>   want to sent the more simple one of them ASAP for consideration
>   (others would not make it in time)
> 
> Tested on top of master (01cdcf783a666481133d4975b1980624b0ef4799)
> on the following platforms with no regression:
>   - powerpc64le-linux-gnu (Power 9) kernel 5.4.0-59
>   - powerpc64le-linux-gnu (Power 9) kernel 5.9.14-1
>   - powerpc64-linux-gnu (Power 9) kernel 5.10.0-1
> 
> [0] https://sourceware.org/pipermail/libc-alpha/2021-January/122027.html
> [1] https://sourceware.org/pipermail/libc-alpha/2021-January/121933.html
> 
> ---- 8< ----
> 
> A not so recent kernel change[1] changed how the trampoline
> `__kernel_sigtramp_rt64` is used to call signal handlers.
> 
> This was exposed on the test misc/tst-sigcontext-get_pc
> 
> Before kernel 5.9, the kernel set LR to the trampoline address and
> jumped directly to the signal handler, and at the end the signal
> handler, as any other function, would `blr` to the address set.  In
> other words, the trampoline was executed just at the end of the signal
> handler and the only thing it did was call sigreturn.  But since
> kernel 5.9 the kernel set CTRL to the signal handler and calls to the
> trampoline code, the trampoline then `bctrl` to the address in CTRL,
> setting the LR to the next instruction in the middle of the
> trampoline, when the signal handler returns, the rest of the
> trampoline code executes the same code as before.
> 
> Here is the full trampoline code as of kernel 5.11.0-rc5 for
> reference:
> 
>     V_FUNCTION_BEGIN(__kernel_sigtramp_rt64)
>     .Lsigrt_start:
>             bctrl▸  /* call the handler */
>             addi▸   r1, r1, __SIGNAL_FRAMESIZE
>             li▸     r0,__NR_rt_sigreturn
>             sc
>     .Lsigrt_end:
>     V_FUNCTION_END(__kernel_sigtramp_rt64)
> 
> This new behavior breaks how `backtrace()` uses to detect the
> trampoline frame to correctly reconstruct the stack frame when it is
> called from inside a signal handling.
> 
> This workaround rely on the fact that the trampoline code is at very
> least two (maybe 3?) instructions in size (as it is in the 32 bits
> version, only on `li` and `sc`), so it is safe to check the return
> address be in the range __kernel_sigtramp_rt64 .. + 4.
> 
> [1] subject: powerpc/64/signal: Balance return predictor stack in signal trampoline
>     commit: 0138ba5783ae0dcc799ad401a1e8ac8333790df9
>     url: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0138ba5783ae0dcc799ad401a1e8ac8333790df9

LGTM, it is ok for 2.33.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  sysdeps/powerpc/powerpc64/backtrace.c | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/sysdeps/powerpc/powerpc64/backtrace.c b/sysdeps/powerpc/powerpc64/backtrace.c
> index ae64c5d7a5..37de9b5bdd 100644
> --- a/sysdeps/powerpc/powerpc64/backtrace.c
> +++ b/sysdeps/powerpc/powerpc64/backtrace.c
> @@ -54,11 +54,22 @@ struct signal_frame_64 {
>    /* We don't care about the rest, since the IP value is at 'uc' field.  */
>  };
>  
> +/* Test if the address match to the inside the trampoline code.
> +   Up to and including kernel 5.8, returning from an interrupt or syscall to a
> +   signal handler starts execution directly at the handler's entry point, with
> +   LR set to address of the sigreturn trampoline (the vDSO symbol).
> +   Newer kernels will branch to signal handler from the trampoline instead, so
> +   checking the stacktrace against the vDSO entrypoint does not work in such
> +   case.
> +   The vDSO branches with a 'bctrl' instruction, so checking either the
> +   vDSO address itself and the next instruction should cover all kernel
> +   versions.  */
>  static inline bool
>  is_sigtramp_address (void *nip)
>  {
>  #ifdef HAVE_SIGTRAMP_RT64
> -  if (nip == GLRO (dl_vdso_sigtramp_rt64))
> +  if (nip == GLRO (dl_vdso_sigtramp_rt64) ||
> +      nip == GLRO (dl_vdso_sigtramp_rt64) + 4)
>      return true;
>  #endif
>    return false;
> 


More information about the Libc-alpha mailing list