[v5,12/22] ia64: Fix Race conditions in pthread cancellation [BZ#12683]

Message ID 20230410204614.4129551-4-adhemerval.zanella@linaro.org (mailing list archive)
State Superseded
Headers
Series Fix Race conditions in pthread cancellation [BZ#12683] |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Adhemerval Zanella April 10, 2023, 8:46 p.m. UTC
  The syscall bridge uses the old brk 0x10000 instruction because by
using the vDSO gate the resulting PC value for an interrupted syscall
points to an address outside the expected markers in
__syscall_cancel_arch.  This is similar to i686 issue.

Also the __syscall_cancel_arch issues the 'break 0x100000' on its own
bundle, and __syscall_cancel_arch_end points to end of the previous one.
It requires an arch-specific ucontext_check_pc_boundary to check for the
ri value (embedded in the sc_ip by the kernel) to check if the syscall
had any side-effects.

Checked on ia64-linux-gnu.
---
 .../sysv/linux/ia64/cancellation-pc-check.h   | 48 +++++++++++
 sysdeps/unix/sysv/linux/ia64/syscall_cancel.S | 81 +++++++++++++++++++
 2 files changed, 129 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h
 create mode 100644 sysdeps/unix/sysv/linux/ia64/syscall_cancel.S
  

Patch

diff --git a/sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h b/sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h
new file mode 100644
index 0000000000..24f05f9759
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h
@@ -0,0 +1,48 @@ 
+/* Architecture specific bits for cancellation handling.
+   Copyright (C) 2023 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/>.  */
+
+#ifndef _NPTL_CANCELLATION_PC_CHECK
+#define _NPTL_CANCELLATION_PC_CHECK 1
+
+/* Check if the program counter (PC) from ucontext CTX is within the start and
+   then end boundary from the __syscall_cancel_arch bridge.  Return TRUE if
+   the PC is within the boundary, meaning the syscall does not have any side
+   effects; or FALSE otherwise.  */
+static bool
+cancellation_pc_check (void *ctx)
+{
+  /* Both are defined in syscall_cancel.S for each architecture.  */
+  extern const char __syscall_cancel_arch_start[1];
+  extern const char __syscall_cancel_arch_end[1];
+
+  uintptr_t sc_ip = ((struct sigcontext *) (ctx))->sc_ip;
+  uintptr_t cr_iip = sc_ip & ~0x3ull;
+  uintptr_t ri = sc_ip & 0x3ull;
+
+  /* IA64 __syscall_cancel_arch issues the 'break 0x100000' on its own bundle,
+     and __syscall_cancel_arch_end points to end of the previous bundle.
+     To check if the syscall had any side-effects we need to check the slot
+     number.  */
+  if (cr_iip == (uintptr_t) __syscall_cancel_arch_end)
+    return ri == 0;
+
+  return cr_iip >= (uintptr_t) __syscall_cancel_arch_start
+	 && cr_iip < (uintptr_t) __syscall_cancel_arch_end;
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/ia64/syscall_cancel.S b/sysdeps/unix/sysv/linux/ia64/syscall_cancel.S
new file mode 100644
index 0000000000..732bf60185
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/ia64/syscall_cancel.S
@@ -0,0 +1,81 @@ 
+/* Cancellable syscall wrapper.  Linux/IA64 version.
+   Copyright (C) 2023 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>
+#include <descr-const.h>
+#undef ret
+
+/* long int __syscall_cancel_arch (int *cancelhandling, long int nr,
+				   long int arg1, long int arg2, long int arg3,
+				   long int arg4, long int arg5, long int arg6)
+*/
+
+ENTRY (__syscall_cancel_arch)
+	.prologue ASM_UNW_PRLG_RP | ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE (8)
+	.mmi
+	.save ar.pfs, r41
+	alloc r41=ar.pfs,8,3,8,0
+	mov r15=r33
+	.save rp, r40
+	mov r40=b0
+	.body
+	.mmi
+	mov r43=r34
+	mov r44=r35
+	mov r45=r36
+	;;
+	.mmi
+	mov r46=r37
+	mov r47=r38
+	mov r48=r39
+	;;
+
+	.global __syscall_cancel_arch_start
+__syscall_cancel_arch_start:
+	;;
+	.mmi
+	nop 0
+	ld4.acq r14=[r32]
+	nop 0
+	;;
+	.mib
+	nop 0
+	tbit.z p6, p7=r14, TCB_CANCELED_BIT
+	.pred.safe_across_calls p1-p63
+(p7)	br.call.dpnt.many b0 = __syscall_do_cancel#
+	.pred.safe_across_calls p1-p5,p16-p63
+	;;
+
+	/* Due instruction bundle ia64 has the end marker before the syscall
+           instruction.  Check IA64 ucontext_check_pc_boundary on how the PC
+           is checked.  */
+	.global __syscall_cancel_arch_end
+__syscall_cancel_arch_end:
+	break 0x100000
+	;;
+	.mmi
+	cmp.ne p6, p7=-1, r10
+	nop 0
+	mov b0=r40
+	;;
+	.mib
+(p7)	sub r8=r0, r8
+	mov ar.pfs=r41
+	br.ret.sptk.many b0
+
+END (__syscall_cancel_arch)