From patchwork Wed Oct 7 16:23:14 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 8982 Received: (qmail 107401 invoked by alias); 7 Oct 2015 16:23:55 -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 107341 invoked by uid 89); 7 Oct 2015 16:23:54 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-yk0-f172.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=bfU0R/EkLdZQLKjT0TVWJzLHcNGtQPTK+he8LwEsSdI=; b=BCfidReWo4hOxyWG+PAGzbRzD74Nv4CXCk3liVVu808TGlPi6iFig67wodr5TnrNH6 ptEYEpaFL2sAWDOc5cAcF5FnnO98pV4WqLcHloY/4q6Vc57OiFmwrBLgZfgVGLiQXmeg D2TrmFzF8xxB3szUaiK6kfDHDDz0CRxyzxk5cSHTAKp6SMatVK78N2lRWXLDBv6H2Z5J ckLBJF3n4puETYfxlk3KeuRZIv+7+YuzJOsQTkQw1qqsRD8b2zWHcO2wuH8P0D9YZ9ir meYieMhtBIZsKAs1mGGL2DwnNbhXzTu3iDNIu1Dvw/dSCCQIaaPxdXFlvh5rdZrYlCHw uxCA== X-Gm-Message-State: ALoCoQmbZApGw+ENUtgDG1H60mVZyb1rqupbiBy0Cere158v5wHDylF+M7HhIiwqFpdX2eGv2yOm X-Received: by 10.13.253.3 with SMTP id n3mr1559944ywf.292.1444235018913; Wed, 07 Oct 2015 09:23:38 -0700 (PDT) From: Adhemerval Zanella X-Google-Original-From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 12/13] nptl: s390: Fix Race conditions in pthread cancellation (BZ#12683) Date: Wed, 7 Oct 2015 13:23:14 -0300 Message-Id: <1444234995-9542-13-git-send-email-adhemerval.zanella@linaro.com> In-Reply-To: <1444234995-9542-1-git-send-email-adhemerval.zanella@linaro.com> References: <1444234995-9542-1-git-send-email-adhemerval.zanella@linaro.com> This patch adds the s390 modifications required for the BZ#12683 fix. It basically removes the enable_asynccancel/disable_asynccancel function usage on code, provide a arch-specific symbol that contains global markers to be used in SIGCANCEL handler. Checked on s390 (thanks to Stefan Liebler ). * sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file. * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine to call __syscall_cancel function for cancellable syscalls. (__pthread_get_ip): Add implementation. * sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (SYSCALL_CANCEL_ERROR): Add definition. (SYSCALL_CANCEL_ERRNO): Likewise. --- ChangeLog | 11 ++ .../unix/sysv/linux/s390/s390-32/syscall_cancel.S | 85 ++++++++++++++ .../unix/sysv/linux/s390/s390-32/sysdep-cancel.h | 128 ++++++++++----------- sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h | 8 ++ 4 files changed, 168 insertions(+), 64 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S diff --git a/ChangeLog b/ChangeLog index f922fa0..cdb4190 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,15 @@ 2015-10-07 Adhemerval Zanella + Stefan Liebler + + * sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine + to call __syscall_cancel function for cancellable syscalls. + (__pthread_get_ip): Add implementation. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (SYSCALL_CANCEL_ERROR): Add + definition. + (SYSCALL_CANCEL_ERRNO): Likewise. + +2015-10-07 Adhemerval Zanella * sysdeps/unix/sysv/linux/arm/syscall_cancel.S: New file. * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO): Redefine diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S b/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S new file mode 100644 index 0000000..bf90acd --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S @@ -0,0 +1,85 @@ +/* Cancellable syscall wrapper - s390 version. + Copyright (C) 2015 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 + +/* long int [r2] __syscall_cancel_arch (int *cancelhandling [r2], + long int nr [r3], + long int arg1 [r4], + long int arg2 [r5], + long int arg3 [r6], + long int arg4 [SP+96], + long int arg5 [SP+100], + long int arg6 [SP+104]) */ + +ENTRY (__syscall_cancel_arch) + /* Save registers and setup stack. */ + stm %r6,%r15,24(%r15) /* Save registers */ + cfi_offset (%r15, -36) + cfi_offset (%r14, -40) + cfi_offset (%r13, -44) + cfi_offset (%r12, -48) + cfi_offset (%r11, -52) + cfi_offset (%r10, -56) + cfi_offset (%r9, -60) + cfi_offset (%r8, -64) + cfi_offset (%r7, -68) + cfi_offset (%r6, -72) + lr %r1,%r15 + l %r0,4(0,%r15) /* Load eos */ + ahi %r15,-96 /* Buy stack space */ + cfi_adjust_cfa_offset (96) + st %r1,0(0,%r15) /* Store back chain */ + st %r0,4(0,%r15) /* Store eos */ + + .globl __syscall_cancel_arch_start + .type __syscall_cancel_arch_start,@function +__syscall_cancel_arch_start: + + /* if (*cancelhandling & CANCELED_BITMASK) + __syscall_do_cancel() */ + tm 3(%r2),4 + jne 1f + + /* Issue a 6 argument syscall */ + lr %r1,%r3 /* Move syscall number. */ + lr %r2,%r4 /* First parameter. */ + lr %r3,%r5 /* Second parameter. */ + lr %r4,%r6 /* Third parameter. */ + l %r5,192(%r15) /* Fourth parameter. */ + l %r6,196(%r15) /* Fifth parameter. */ + l %r7,200(%r15) /* Sixth parameter. */ + + svc 0 /* svc number is always in r1. */ + .globl __syscall_cancel_arch_end + .type __syscall_cancel_arch_end,@function +__syscall_cancel_arch_end: + l %r15,0(%r15) /* Load back chain. */ + cfi_adjust_cfa_offset (-96) + lm %r6,15,24(%r15) /* Load registers. */ + + br %r14 + + /* Branch to __syscall_do_cancel */ +1: + l %r15,0(%r15) /* Load back chain. */ + cfi_adjust_cfa_offset (-96) + lm %r6,%r15,24(%r15) /* Load registers. */ + jg __syscall_do_cancel +END (__syscall_cancel_arch) +libc_hidden_def (__syscall_cancel_arch) diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h index 17b7aaa..1ed57f0 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h +++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h @@ -24,97 +24,90 @@ #if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt) +# if IS_IN (libc) +# define PREPARE_CALL +# define PREPARE_GOT +# define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel) +# else +# define PREPARE_CALL l %r12,2f-0b(%r13); \ + la %r12,0(%r12,%r13); +# define PREPARE_GOT 2: .long _GLOBAL_OFFSET_TABLE_-0b; +# define JMP_SYSCALL_CANCEL __syscall_cancel@plt +# endif + +# define STORE_0 /* Nothing */ +# define STORE_1 /* Nothing */ +# define STORE_2 /* Nothing */ +# define STORE_3 /* Nothing */ +# define STORE_4 st %r6,24(%r15); \ + cfi_offset (%r6,-72); +# define STORE_5 STORE_4 +# define STORE_6 STORE_4 + +# define LOAD_0 /* Nothing */ +# define LOAD_1 /* Nothing */ +# define LOAD_2 /* Nothing */ +# define LOAD_3 /* Nothing */ +# define LOAD_4 l %r6,24(%r15); +# define LOAD_5 LOAD_4 +# define LOAD_6 LOAD_4 + +# define MOVE_ARGS_0 +# define MOVE_ARGS_1 lr %r3,%r2; \ + MOVE_ARGS_0 +# define MOVE_ARGS_2 lr %r4,%r3; \ + MOVE_ARGS_1 +# define MOVE_ARGS_3 lr %r5,%r4; \ + MOVE_ARGS_2 +# define MOVE_ARGS_4 lr %r6,%r5; \ + MOVE_ARGS_3 +# define MOVE_ARGS_5 st %r6,96(%r15); \ + MOVE_ARGS_4 +# define MOVE_ARGS_6 l %r14,96(%r14); \ + st %r14,100(%r15); \ + MOVE_ARGS_5 + # undef PSEUDO # define PSEUDO(name, syscall_name, args) \ .text; \ L(pseudo_cancel): \ cfi_startproc; \ - STM_##args \ stm %r12,%r15,48(%r15); \ cfi_offset (%r15, -36); \ cfi_offset (%r14, -40); \ cfi_offset (%r13, -44); \ cfi_offset (%r12, -48); \ + STORE_##args \ lr %r14,%r15; \ - ahi %r15,-96; \ - cfi_adjust_cfa_offset (96); \ + ahi %r15,-104; \ + cfi_adjust_cfa_offset (104); \ st %r14,0(%r15); \ + MOVE_ARGS_##args \ + lhi %r2,SYS_ify (syscall_name); \ basr %r13,0; \ 0: l %r1,1f-0b(%r13); \ + PREPARE_CALL \ bas %r14,0(%r1,%r13); \ - lr %r0,%r2; \ - LM_##args \ - .if SYS_ify (syscall_name) < 256; \ - svc SYS_ify (syscall_name); \ - .else; \ - lhi %r1,SYS_ify (syscall_name); \ - svc 0; \ - .endif; \ - LR7_##args \ - l %r1,2f-0b(%r13); \ - lr %r12,%r2; \ - lr %r2,%r0; \ - bas %r14,0(%r1,%r13); \ - lr %r2,%r12; \ - lm %r12,%r15,48+96(%r15); \ + lm %r12,%r15,48+104(%r15); \ + cfi_restore (%r12); \ + cfi_restore (%r13); \ + cfi_restore (%r14); \ + cfi_restore (%r15); \ + LOAD_##args \ cfi_endproc; \ j L(pseudo_check); \ -1: .long CENABLE-0b; \ -2: .long CDISABLE-0b; \ +1: .long JMP_SYSCALL_CANCEL-0b; \ + PREPARE_GOT \ ENTRY(name) \ SINGLE_THREAD_P(%r1) \ jne L(pseudo_cancel); \ -.type __##syscall_name##_nocancel,@function; \ -.globl __##syscall_name##_nocancel; \ -__##syscall_name##_nocancel: \ DO_CALL(syscall_name, args); \ L(pseudo_check): \ lhi %r4,-4095; \ clr %r2,%r4; \ jnl SYSCALL_ERROR_LABEL; \ -.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ L(pseudo_end): -# if IS_IN (libpthread) -# define CENABLE __pthread_enable_asynccancel -# define CDISABLE __pthread_disable_asynccancel -# elif IS_IN (libc) -# define CENABLE __libc_enable_asynccancel -# define CDISABLE __libc_disable_asynccancel -# elif IS_IN (librt) -# define CENABLE __librt_enable_asynccancel -# define CDISABLE __librt_disable_asynccancel -# else -# error Unsupported library -# endif - -#define STM_0 /* Nothing */ -#define STM_1 st %r2,8(%r15); -#define STM_2 stm %r2,%r3,8(%r15); -#define STM_3 stm %r2,%r4,8(%r15); -#define STM_4 stm %r2,%r5,8(%r15); -#define STM_5 stm %r2,%r5,8(%r15); -#define STM_6 stm %r2,%r7,8(%r15); - -#define LM_0 /* Nothing */ -#define LM_1 l %r2,8+96(%r15); -#define LM_2 lm %r2,%r3,8+96(%r15); -#define LM_3 lm %r2,%r4,8+96(%r15); -#define LM_4 lm %r2,%r5,8+96(%r15); -#define LM_5 lm %r2,%r5,8+96(%r15); -#define LM_6 lm %r2,%r5,8+96(%r15); \ - cfi_offset (%r7, -68); \ - l %r7,96+96(%r15); - -#define LR7_0 /* Nothing */ -#define LR7_1 /* Nothing */ -#define LR7_2 /* Nothing */ -#define LR7_3 /* Nothing */ -#define LR7_4 /* Nothing */ -#define LR7_5 /* Nothing */ -#define LR7_6 l %r7,28+96(%r15); \ - cfi_restore (%r7); - # ifndef __ASSEMBLER__ # define SINGLE_THREAD_P \ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ @@ -136,4 +129,11 @@ L(pseudo_end): # define RTLD_SINGLE_THREAD_P \ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ header.multiple_threads) == 0, 1) + +static inline +long int __pthread_get_ip (const struct ucontext *uc) +{ + /* We have 31bit addresses, remove bit 0. */ + return uc->uc_mcontext.psw.addr & 0x7FFFFFFF; +} #endif diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h index c768df1..08e2be4 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h +++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h @@ -243,6 +243,14 @@ #undef INTERNAL_SYSCALL_ERRNO #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) +#undef SYSCALL_CANCEL_ERROR +#define SYSCALL_CANCEL_ERROR(__val) \ + ((unsigned int) (__val) >= 0xfffff001u) + +#undef SYSCALL_CANCEL_ERRNO +#define SYSCALL_CANCEL_ERRNO(__val) \ + (-(__val)) + #define DECLARGS_0() #define DECLARGS_1(arg1) \ register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);