[v2,07/21] nptl: powerpc: Fix Race conditions in pthread cancellation (BZ#12683)
Commit Message
This patches adds the powerpc64 modification required for the BZ#12683.
It basically adds the required __pthread_get_pc function and a arch
specific syscall_cancel implementation.
The powerpc requires an arch-specific syscall_cancel because
INTERNAL_SYSCALL_NCS adds a mfcr just after the sc instruction to get
the CR0.SO bit information from kernel (which signals the error
return status). So for cancelled syscalls with side effects,
__pthread_get_pc will point to mcfr and thus invalidating the checks
on sigcancel_handler.
Checked on powerpc64le-linux-gnu and powerpc-linux-gnu.
[BZ #12683]
* sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/powerpc/sysdep-cancel.h
(__pthread_get_pc): New function.
---
ChangeLog | 5 ++
sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h | 16 ++++++
sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S | 64 ++++++++++++++++++++++++
3 files changed, 85 insertions(+)
create mode 100644 sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
Comments
Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> This patches adds the powerpc64 modification required for the BZ#12683.
> It basically adds the required __pthread_get_pc function and a arch
> specific syscall_cancel implementation.
>
> The powerpc requires an arch-specific syscall_cancel because
> INTERNAL_SYSCALL_NCS adds a mfcr just after the sc instruction to get
> the CR0.SO bit information from kernel (which signals the error
> return status). So for cancelled syscalls with side effects,
> __pthread_get_pc will point to mcfr and thus invalidating the checks
> on sigcancel_handler.
>
> Checked on powerpc64le-linux-gnu and powerpc-linux-gnu.
>
> [BZ #12683]
> * sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file.
> * sysdeps/unix/sysv/linux/powerpc/sysdep-cancel.h
> (__pthread_get_pc): New function.
This entry is outdated. Both the file name and the function name need to be
updated.
> diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
> new file mode 100644
> index 0000000..2e56c72
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
> @@ -0,0 +1,64 @@
> +/* Cancellable syscall wrapper. Linux/powerpc version.
> + Copyright (C) 2017 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <sysdep.h>
> +
> +/* long int [r3] __syscall_cancel_arch (int *cancelhandling [r3],
> + long int nr [r4],
> + long int arg1 [r5],
> + long int arg2 [r6],
> + long int arg3 [r7],
> + long int arg4 [r8],
> + long int arg5 [r9],
> + long int arg6 [r10]) */
> +
> +ENTRY (__syscall_cancel_arch)
> +
> + .globl __syscall_cancel_arch_start
> + .type __syscall_cancel_arch_start,@function
> +__syscall_cancel_arch_start:
> +
> + /* if (*cancelhandling & CANCELED_BITMASK)
> + __syscall_do_cancel() */
> + lwz r0,0(r3)
> + rldicl. r0,r0,62,63
> + beq 1f
> + b __syscall_do_cancel
Should this be a Branch & Link?
On 07/05/2018 16:25, Tulio Magno Quites Machado Filho wrote:
> Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
>
>> This patches adds the powerpc64 modification required for the BZ#12683.
>> It basically adds the required __pthread_get_pc function and a arch
>> specific syscall_cancel implementation.
>>
>> The powerpc requires an arch-specific syscall_cancel because
>> INTERNAL_SYSCALL_NCS adds a mfcr just after the sc instruction to get
>> the CR0.SO bit information from kernel (which signals the error
>> return status). So for cancelled syscalls with side effects,
>> __pthread_get_pc will point to mcfr and thus invalidating the checks
>> on sigcancel_handler.
>>
>> Checked on powerpc64le-linux-gnu and powerpc-linux-gnu.
>>
>> [BZ #12683]
>> * sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file.
>> * sysdeps/unix/sysv/linux/powerpc/sysdep-cancel.h
>> (__pthread_get_pc): New function.
>
> This entry is outdated. Both the file name and the function name need to be
> updated.
Ack.
>
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
>> new file mode 100644
>> index 0000000..2e56c72
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
>> @@ -0,0 +1,64 @@
>> +/* Cancellable syscall wrapper. Linux/powerpc version.
>> + Copyright (C) 2017 Free Software Foundation, Inc.
>> + This file is part of the GNU C Library.
>> +
>> + The GNU C Library is free software; you can redistribute it and/or
>> + modify it under the terms of the GNU Lesser General Public
>> + License as published by the Free Software Foundation; either
>> + version 2.1 of the License, or (at your option) any later version.
>> +
>> + The GNU C Library is distributed in the hope that it will be useful,
>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + Lesser General Public License for more details.
>> +
>> + You should have received a copy of the GNU Lesser General Public
>> + License along with the GNU C Library; if not, see
>> + <http://www.gnu.org/licenses/>. */
>> +
>> +#include <sysdep.h>
>> +
>> +/* long int [r3] __syscall_cancel_arch (int *cancelhandling [r3],
>> + long int nr [r4],
>> + long int arg1 [r5],
>> + long int arg2 [r6],
>> + long int arg3 [r7],
>> + long int arg4 [r8],
>> + long int arg5 [r9],
>> + long int arg6 [r10]) */
>> +
>> +ENTRY (__syscall_cancel_arch)
>> +
>> + .globl __syscall_cancel_arch_start
>> + .type __syscall_cancel_arch_start,@function
>> +__syscall_cancel_arch_start:
>> +
>> + /* if (*cancelhandling & CANCELED_BITMASK)
>> + __syscall_do_cancel() */
>> + lwz r0,0(r3)
>> + rldicl. r0,r0,62,63
>> + beq 1f
>> + b __syscall_do_cancel
>
> Should this be a Branch & Link?
>
Right, I think ABI really mandates branch & link even for no-return calls.
I will change it.
@@ -15,7 +15,11 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#ifndef _SIGCONTEXTINFO_H
+#define _SIGCONTEXTINFO_H
+
#include <signal.h>
+#include <stdint.h>
#define SIGCONTEXT struct sigcontext *
#define SIGCONTEXT_EXTRA_ARGS
@@ -24,3 +28,15 @@
#define GET_STACK(ctx) ((void *)((ctx)->regs->gpr[1]))
#define CALL_SIGHANDLER(handler, signo, ctx) \
(handler)((signo), SIGCONTEXT_EXTRA_ARGS (ctx))
+
+static inline uintptr_t
+ucontext_get_pc (const ucontext_t *uc)
+{
+#ifdef __powerpc64__
+ return uc->uc_mcontext.gp_regs[PT_NIP];
+#else
+ return uc->uc_mcontext.uc_regs->gregs[PT_NIP];
+#endif
+}
+
+#endif /* _SIGCONTEXTINFO_H */
new file mode 100644
@@ -0,0 +1,64 @@
+/* Cancellable syscall wrapper. Linux/powerpc version.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [r3] __syscall_cancel_arch (int *cancelhandling [r3],
+ long int nr [r4],
+ long int arg1 [r5],
+ long int arg2 [r6],
+ long int arg3 [r7],
+ long int arg4 [r8],
+ long int arg5 [r9],
+ long int arg6 [r10]) */
+
+ENTRY (__syscall_cancel_arch)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ lwz r0,0(r3)
+ rldicl. r0,r0,62,63
+ beq 1f
+ b __syscall_do_cancel
+ nop
+1:
+ ABORT_TRANSACTION
+ /* Issue a 6 argument syscall, the nr [r4] being the syscall
+ number. */
+ mr r0,r4
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+ sc
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+
+ bnslr+
+ neg r3,r3
+ blr
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)