From patchwork Mon Feb 26 21:03:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 26096 Received: (qmail 80086 invoked by alias); 26 Feb 2018 21:04:31 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 78453 invoked by uid 89); 26 Feb 2018 21:04:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mail-qk0-f195.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=JLo3wp3BnEwAwjeeDPPFI8lxnv6XHwbggPVGbI6mcZ0=; b=X750nj/8tNGP01Z1yJkoeo9HFQTCskiQfzxp+mncC1OkRoAzcPPCcYcs3liXBmX6kb 4/AZC71pS/CowzXNXdk63SADEnOp8JBTfwsvX7/Teq8xT72bMKBlp+bqXLpE/189JN48 27k1fN2NoQNSSyxNpVxHcsaCL8MOjRpp23qewg9Fo6s2hdKPayRZLyI4RuWPXt4Vk5Bb lYC81UD42EoR3GXSN2nsWcKXogyoLUgwqA6tIMbvc0GjXx7GV9LiaCC3sF+8fwsrW1Jk C9J8bnlKXwb/fuPFY0rV/jSC29e2PrHUuSZWcF4J/wIMbdJQrcxcaHG2PX1rg1/whvEP 9zKA== X-Gm-Message-State: APf1xPC/DtucO8X/I0u+uaZU+mhaDt3vZOTgz+jlP4aSqroyCU3dgFNN Xfn9jtalPOyhxRAx9vsAjCHdw7uE2n4= X-Google-Smtp-Source: AG47ELsAr4P4NqRJCl7k0Tum76ca+94VjQK6ZIbF0LP6exsjL4Lc8cDy6KOGOCjgVvny5TSuq/X+mQ== X-Received: by 10.55.72.203 with SMTP id v194mr19705058qka.170.1519679052320; Mon, 26 Feb 2018 13:04:12 -0800 (PST) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 19/21] nptl: mips: Fix Race conditions in pthread cancellation (BZ#12683) Date: Mon, 26 Feb 2018 18:03:34 -0300 Message-Id: <1519679016-12241-20-git-send-email-adhemerval.zanella@linaro.org> In-Reply-To: <1519679016-12241-1-git-send-email-adhemerval.zanella@linaro.org> References: <1519679016-12241-1-git-send-email-adhemerval.zanella@linaro.org> This patch adds the mips modifications required for the BZ#12683. It adds the required ucontext_get_pc function, a mips32 cancellable syscall wrapper and 7 argument cancellable syscall support. To avoid code pessimization and add a requirement on all architectures to support {INLINE,INTERNAL)_SYSCALL with 7 argument, its support is added through a flag, HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS, which changes the signature and prototype of the requires macros and functions (SYSCALL_CANCEL, __syscall_cancel and __syscall_cancel_arch). As default 6 arguments cancellable syscalls are use. MIPS o32 requires an arch-specific implementation because INTERNAL_SYSCALL_NCS adds an 'addiu' just after the syscall instruction which invalidates the checks on sigcancel_handler. Checked against a build and make check run-built-tests=no for mips-gnu-linux, mips64-linux-gnu, mips64-n32-linux-gnu. I also ran some basic o32 and n64 cancellation tests on a simulated mips64 qemu system. [BZ #12683] * nptl/libc-cancellation.c (__syscall_cancel): Define and use 7 argument syscall if architecture requires it. * nptl/pthreadP.h (__syscall_cancel_arch): Likewise. * sysdeps/unix/sysdep.h (__syscall_cancel, __SYSCALL_CANCEL*): Define with 7 argument if architecture requires it. (__SYSCALL_CANCEL7_ARG_DEF): New macro. (__SYSCALL_CANCEL7_ARG): Likewise. (__SYSCALL_CANCEL7_ARG7): Likewise. * sysdeps/unix/sysv/linux/syscall_cancel.c (__syscall_cancel_arch): Likewise. * sysdeps/mips/nptl/tls.h (READ_THREAD_POINTER): Check __mips_isa_rev existance for macro definition. * sysdeps/unix/sysv/linux/mips/sigcontextinfo.h (ucontext_get_pc): New function. * sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S: New file. * sysdeps/unix/sysv/linux/mips/mips32/sysdep.h (HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS): Define. --- ChangeLog | 19 +++ nptl/libc-cancellation.c | 7 +- nptl/pthreadP.h | 3 +- sysdeps/mips/nptl/tls.h | 2 +- sysdeps/unix/sysdep.h | 38 ++++-- .../unix/sysv/linux/mips/mips32/syscall_cancel.S | 128 +++++++++++++++++++++ sysdeps/unix/sysv/linux/mips/mips32/sysdep.h | 4 + sysdeps/unix/sysv/linux/mips/sigcontextinfo.h | 13 ++- sysdeps/unix/sysv/linux/syscall_cancel.c | 6 +- 9 files changed, 204 insertions(+), 16 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S diff --git a/nptl/libc-cancellation.c b/nptl/libc-cancellation.c index 9b054aa..beb433c 100644 --- a/nptl/libc-cancellation.c +++ b/nptl/libc-cancellation.c @@ -25,7 +25,7 @@ long int __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1, __syscall_arg_t a2, __syscall_arg_t a3, __syscall_arg_t a4, __syscall_arg_t a5, - __syscall_arg_t a6) + __syscall_arg_t a6 __SYSCALL_CANCEL7_ARG_DEF) { pthread_t self = (pthread_t) THREAD_SELF; volatile struct pthread *pd = (volatile struct pthread *) self; @@ -35,7 +35,8 @@ __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1, if (pd->cancelhandling & CANCELSTATE_BITMASK) { INTERNAL_SYSCALL_DECL (err); - result = INTERNAL_SYSCALL_NCS_CALL (nr, err, a1, a2, a3, a4, a5, a6); + result = INTERNAL_SYSCALL_NCS_CALL (nr, err, a1, a2, a3, a4, a5, a6 + __SYSCALL_CANCEL7_ARG7); if (INTERNAL_SYSCALL_ERROR_P (result, err)) return -INTERNAL_SYSCALL_ERRNO (result, err); return result; @@ -44,7 +45,7 @@ __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1, /* Call the arch-specific entry points that contains the globals markers to be checked by SIGCANCEL handler. */ result = __syscall_cancel_arch (&pd->cancelhandling, nr, a1, a2, a3, a4, a5, - a6); + a6 __SYSCALL_CANCEL7_ARG7); if ((result == -EINTR) && (pd->cancelhandling & CANCELED_BITMASK) diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index bb7ff81..448abea 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -317,7 +317,8 @@ __do_cancel (void) extern long int __syscall_cancel_arch (volatile int *, __syscall_arg_t nr, __syscall_arg_t arg1, __syscall_arg_t arg2, __syscall_arg_t arg3, - __syscall_arg_t arg4, __syscall_arg_t arg5, __syscall_arg_t arg6); + __syscall_arg_t arg4, __syscall_arg_t arg5, __syscall_arg_t arg6 + __SYSCALL_CANCEL7_ARG_DEF); libc_hidden_proto (__syscall_cancel_arch); extern void __syscall_do_cancel (void) diff --git a/sysdeps/mips/nptl/tls.h b/sysdeps/mips/nptl/tls.h index 5f8cd21..d037cb8 100644 --- a/sysdeps/mips/nptl/tls.h +++ b/sysdeps/mips/nptl/tls.h @@ -35,7 +35,7 @@ # define READ_THREAD_POINTER() (__builtin_thread_pointer ()) #else /* Note: rd must be $v1 to be ABI-conformant. */ -# if __mips_isa_rev >= 2 +# if defined __mips_isa_rev && __mips_isa_rev >= 2 # define READ_THREAD_POINTER() \ ({ void *__result; \ asm volatile ("rdhwr\t%0, $29" : "=v" (__result)); \ diff --git a/sysdeps/unix/sysdep.h b/sysdeps/unix/sysdep.h index cea81a5..42720c5 100644 --- a/sysdeps/unix/sysdep.h +++ b/sysdeps/unix/sysdep.h @@ -121,29 +121,51 @@ typedef long int __syscall_arg_t; # define __SSC(__x) ((__syscall_arg_t) (__x)) #endif +/* Adjust both the __syscall_cancel and the SYSCALL_CANCEL macro to support + 7 arguments instead of default 6 (for some architectures like mip32). + We need it because using 7 arguments for all architecture would require + then to implement both {INTERNAL,INLINE}_SYSCALL and __syscall_cancel_arch + to accept 7 arguments. */ +#ifdef HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS +# define __SYSCALL_CANCEL7_ARG_DEF , __syscall_arg_t arg7 +# define __SYSCALL_CANCEL7_ARG , 0 +# define __SYSCALL_CANCEL7_ARG7 , arg7 +#else +# define __SYSCALL_CANCEL7_ARG_DEF +# define __SYSCALL_CANCEL7_ARG +# define __SYSCALL_CANCEL7_ARG7 +#endif + long int __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t arg1, __syscall_arg_t arg2, __syscall_arg_t arg3, __syscall_arg_t arg4, __syscall_arg_t arg5, - __syscall_arg_t arg6); + __syscall_arg_t arg6 __SYSCALL_CANCEL7_ARG_DEF); libc_hidden_proto (__syscall_cancel); #define __SYSCALL_CANCEL0(name) \ - (__syscall_cancel)(__NR_##name, 0, 0, 0, 0, 0, 0) + (__syscall_cancel)(__NR_##name, 0, 0, 0, 0, 0, 0 \ + __SYSCALL_CANCEL7_ARG) #define __SYSCALL_CANCEL1(name, a1) \ - (__syscall_cancel)(__NR_##name, __SSC(a1), 0, 0, 0, 0, 0) + (__syscall_cancel)(__NR_##name, __SSC(a1), 0, 0, 0, 0, 0 \ + __SYSCALL_CANCEL7_ARG) #define __SYSCALL_CANCEL2(name, a1, a2) \ - (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), 0, 0, 0, 0) + (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), 0, 0, 0, 0 \ + __SYSCALL_CANCEL7_ARG) #define __SYSCALL_CANCEL3(name, a1, a2, a3) \ - (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), 0, 0, 0) + (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), 0, 0, 0 \ + __SYSCALL_CANCEL7_ARG) #define __SYSCALL_CANCEL4(name, a1, a2, a3, a4) \ (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \ - __SSC(a4), 0, 0) + __SSC(a4), 0, 0 __SYSCALL_CANCEL7_ARG) #define __SYSCALL_CANCEL5(name, a1, a2, a3, a4, a5) \ (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \ - __SSC(a4), __SSC(a5), 0) + __SSC(a4), __SSC(a5), 0 __SYSCALL_CANCEL7_ARG) #define __SYSCALL_CANCEL6(name, a1, a2, a3, a4, a5, a6) \ (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \ - __SSC(a4), __SSC(a5), __SSC(a6)) + __SSC(a4), __SSC(a5), __SSC(a6) __SYSCALL_CANCEL7_ARG) +#define __SYSCALL_CANCEL7(name, a1, a2, a3, a4, a5, a6, a7) \ + (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \ + __SSC(a4), __SSC(a5), __SSC(a6), __SSC(a7)) #define __SYSCALL_CANCEL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n #define __SYSCALL_CANCEL_NARGS(...) \ diff --git a/sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S b/sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S new file mode 100644 index 0000000..75c4390 --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S @@ -0,0 +1,128 @@ +/* Cancellable syscall wrapper. Linux/mips32 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 + . */ + +#include +#include + +/* long int __syscall_cancel_arch (int *cancelhandling, + __syscall_arg_t nr, + __syscall_arg_t arg1, + __syscall_arg_t arg2, + __syscall_arg_t arg3, + __syscall_arg_t arg4, + __syscall_arg_t arg5, + __syscall_arg_t arg6, + __syscall_arg_t arg7) */ + +#define FRAME_SIZE 56 + +NESTED (__syscall_cancel_arch, FRAME_SIZE, fp) + .mask 0xc0070000,-SZREG + .fmask 0x00000000,0 + + PTR_ADDIU sp, -FRAME_SIZE + cfi_def_cfa_offset (FRAME_SIZE) + + sw fp,48(sp) + sw ra,52(sp) + sw s2,44(sp) + sw s1,40(sp) + sw s0,36(sp) +#ifdef __PIC__ + .cprestore 16 +#endif + cfi_offset (31, -4) + cfi_offset (30, -8) + cfi_offset (18, -12) + cfi_offset (17, -16) + cfi_offset (16, -20) + move fp,sp + cfi_def_cfa_register (30) + + .globl __syscall_cancel_arch_start + .type __syscall_cancel_arch_start, @function +__syscall_cancel_arch_start: + + lw v0,0(a0) + andi v0,v0,0x4 + bne v0,zero,2f + + addiu sp,sp,-16 + addiu v0,sp,16 + sw v0,24(fp) + + move s0,a1 + move a0,a2 + move a1,a3 + lw a2,72(fp) + lw a3,76(fp) + lw v0,84(fp) + lw s1,80(fp) + lw s2,88(fp) + + .set noreorder + subu sp, 32 + sw s1, 16(sp) + sw v0, 20(sp) + sw s2, 24(sp) + move v0, $16 + syscall + + .globl __syscall_cancel_arch_end + .type __syscall_cancel_arch_end, @function +__syscall_cancel_arch_end: + addiu sp, 32 + .set reorder + + beq a3,zero,1f + subu v0,zero,v0 +1: + move sp,fp + cfi_remember_state + cfi_def_cfa_register (29) + lw ra,52(fp) + lw fp,48(sp) + lw s2,44(sp) + lw s1,40(sp) + lw s0,36(sp) + .set noreorder + .set nomacro + jr ra + addiu sp,sp,FRAME_SIZE + + .set macro + .set reorder + + cfi_def_cfa_offset (0) + cfi_restore (16) + cfi_restore (17) + cfi_restore (18) + cfi_restore (30) + cfi_restore (31) + +2: + cfi_restore_state +#ifdef __PIC__ + PTR_LA t9, __syscall_do_cancel + jalr t9 +#else + jal __syscall_do_cancel +#endif + +END (__syscall_cancel_arch) +libc_hidden_def (__syscall_cancel_arch) diff --git a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h index cbe9cd2..5417c43 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h +++ b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h @@ -18,6 +18,10 @@ #ifndef _LINUX_MIPS_MIPS32_SYSDEP_H #define _LINUX_MIPS_MIPS32_SYSDEP_H 1 +/* mips32 have cancelable syscalls with 7 arguments (currently only + sync_file_range). */ +#define HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS 1 + /* There is some commonality. */ #include #include diff --git a/sysdeps/unix/sysv/linux/mips/sigcontextinfo.h b/sysdeps/unix/sysv/linux/mips/sigcontextinfo.h index d183a33..7da55f5 100644 --- a/sysdeps/unix/sysv/linux/mips/sigcontextinfo.h +++ b/sysdeps/unix/sysv/linux/mips/sigcontextinfo.h @@ -16,7 +16,10 @@ License along with the GNU C Library. If not, see . */ +#ifndef _SIGCONTEXTINFO_H +#define _SIGCONTEXTINFO_H +#include #include #if _MIPS_SIM == _ABIO32 @@ -39,4 +42,12 @@ #define CALL_SIGHANDLER(handler, signo, ctx) \ (handler)((signo), SIGCONTEXT_EXTRA_ARGS (ctx)) -#endif +#endif /* _MIPS_SIM == _ABIO32 */ + +static inline uintptr_t +ucontext_get_pc (const ucontext_t *uc) +{ + return uc->uc_mcontext.pc; +} + +#endif /* _SIGCONTEXTINFO_H */ diff --git a/sysdeps/unix/sysv/linux/syscall_cancel.c b/sysdeps/unix/sysv/linux/syscall_cancel.c index ac08bb7..5a3d383 100644 --- a/sysdeps/unix/sysv/linux/syscall_cancel.c +++ b/sysdeps/unix/sysv/linux/syscall_cancel.c @@ -46,14 +46,16 @@ long int __syscall_cancel_arch (volatile int *ch, __syscall_arg_t nr, __syscall_arg_t a1, __syscall_arg_t a2, __syscall_arg_t a3, __syscall_arg_t a4, - __syscall_arg_t a5, __syscall_arg_t a6) + __syscall_arg_t a5, __syscall_arg_t a6 + __SYSCALL_CANCEL7_ARG_DEF) { ADD_LABEL ("__syscall_cancel_arch_start"); if (__glibc_unlikely (*ch & CANCELED_BITMASK)) __syscall_do_cancel(); INTERNAL_SYSCALL_DECL(err); - long int result = INTERNAL_SYSCALL_NCS (nr, err, 6, a1, a2, a3, a4, a5, a6); + long int result = INTERNAL_SYSCALL_NCS_CALL (nr, err, a1, a2, a3, a4, a5, + a6 __SYSCALL_CANCEL7_ARG7); ADD_LABEL ("__syscall_cancel_arch_end"); if (INTERNAL_SYSCALL_ERROR_P (result, err)) return -INTERNAL_SYSCALL_ERRNO (result, err);