[v2,07/21] nptl: powerpc: Fix Race conditions in pthread cancellation (BZ#12683)

Message ID 1519679016-12241-8-git-send-email-adhemerval.zanella@linaro.org
State Dropped
Delegated to: Tulio Magno Quites Machado Filho
Headers

Commit Message

Adhemerval Zanella Feb. 26, 2018, 9:03 p.m. UTC
  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

Tulio Magno Quites Machado Filho May 7, 2018, 7:25 p.m. UTC | #1
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?
  
Adhemerval Zanella May 8, 2018, 6:07 p.m. UTC | #2
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.
  

Patch

diff --git a/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h b/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h
index 72381e3..3be71f7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h
+++ b/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h
@@ -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  */
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
+	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)