From patchwork Mon Jul 31 17:18:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 1815199 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=MwNYni4r; dkim-atps=neutral Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RF4kL2gJLz1yfG for ; Tue, 1 Aug 2023 03:20:10 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 252A7385782B for ; Mon, 31 Jul 2023 17:20:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 252A7385782B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1690824008; bh=QMIazJYqVuyucDGD7gnDiVlujQudCH0UCwV20cgOTbU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=MwNYni4ryr1L3mtbLhX9k8d0Pd5dio8hwxkGnMrkmlgW2kn2o6k2lvmk9plhURrJS z1nR/RcC1Zd6sHZxrmdQfRHNy9RwsKSlRuSz5Hlmj1TQm+XIbSLjElznFj1hD49m32 i3Sl78hJ7Yd4W7WBLj8mgPuxHkr0C0IhvBsNamBk= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-oi1-x236.google.com (mail-oi1-x236.google.com [IPv6:2607:f8b0:4864:20::236]) by sourceware.org (Postfix) with ESMTPS id 8EE3E3858C53 for ; Mon, 31 Jul 2023 17:19:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8EE3E3858C53 Received: by mail-oi1-x236.google.com with SMTP id 5614622812f47-3a3efee1d44so3748788b6e.3 for ; Mon, 31 Jul 2023 10:19:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690823947; x=1691428747; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QMIazJYqVuyucDGD7gnDiVlujQudCH0UCwV20cgOTbU=; b=A/HEg45MRPhKf/NWrAAbpAcBsk3iyFbPsWf8zm7KH4XY8uhypWoU8PeglN1k3AwTYM ebUXoiKwYI9/DBkNrHidokdNGT2Ovaq2e3bXtASa0yHAU7R89XfN+g5LaXGftKm5lbLW mHkiWnecfI1rJqL/aJoF+0cYR6khqVWP2YnZvR6rCBhz4WxgRwTnoLH3XftTpv4mD0er 5l3Xef4VRyfyUgQZ1CeHZkBk5/MfVo27InbBruzntiOcv/ark2RjHS4uSB/d3omXdD2J EGmAFCmJo2wh7V+iRyGwQ5azzqE8frWYVb7ZJxPIihfU1FVTrU0G4q9cIl6pXeT27jOT BOZg== X-Gm-Message-State: ABy/qLY98+AUW26rvpIpEGODIJnukAygRhSfmUTqbbNcRt2FzScdHvrM h8Cx0KG3czFl82Zg7T07gwkE7g7VwIA7ZKjPTRVd6w== X-Google-Smtp-Source: APBJJlFQA2S7xN4rT1nZidVETa3k1KDAFJ5OUO5l6kW+gpFGW994ZnETyySFPCTtFYa2A0vdqJwP6Q== X-Received: by 2002:a05:6808:347:b0:3a7:1e40:6ce9 with SMTP id j7-20020a056808034700b003a71e406ce9mr6813360oie.26.1690823947197; Mon, 31 Jul 2023 10:19:07 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:440b:68be:64f1:9a6f:2423]) by smtp.gmail.com with ESMTPSA id k16-20020a05680808d000b003a724566afdsm1560047oij.20.2023.07.31.10.19.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Jul 2023 10:19:06 -0700 (PDT) To: libc-alpha@sourceware.org, Carlos O'Donell Subject: [PATCH 1/2] setjmp: Use BSD sematic as default for setjmp Date: Mon, 31 Jul 2023 14:18:59 -0300 Message-Id: <20230731171900.4065501-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230731171900.4065501-1-adhemerval.zanella@linaro.org> References: <20230731171900.4065501-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" POSIX relaxed the relation of setjmp/longjmp and the signal mask save/restore, meaning that setjmp does not require to be routed to _setjmp to be standard compliant. This is done to avoid breakage of SIGABRT handlers, since to fully make abort AS-safe, it is required to remove the recurisve lock used to unblock SIGABRT prior raised the signal. Also, it allows caller to actually use setjmp, since from 7011c2622fe3e10a29dbe74f06aaebd07710127d the symbol is unconditionally routed to _setjmp. Checked on x86_64-linux-gnu. --- manual/setjmp.texi | 14 ++++---------- nptl/pthread_create.c | 3 ++- setjmp/setjmp.h | 5 ----- sysdeps/nptl/libc_start_call_main.h | 3 ++- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/manual/setjmp.texi b/manual/setjmp.texi index 7092a0dde2..f2d82a2f33 100644 --- a/manual/setjmp.texi +++ b/manual/setjmp.texi @@ -189,16 +189,10 @@ them @code{volatile}. @section Non-Local Exits and Signals In BSD Unix systems, @code{setjmp} and @code{longjmp} also save and -restore the set of blocked signals; see @ref{Blocking Signals}. However, -the POSIX.1 standard requires @code{setjmp} and @code{longjmp} not to -change the set of blocked signals, and provides an additional pair of -functions (@code{sigsetjmp} and @code{siglongjmp}) to get the BSD -behavior. - -The behavior of @code{setjmp} and @code{longjmp} in @theglibc{} is -controlled by feature test macros; see @ref{Feature Test Macros}. The -default in @theglibc{} is the POSIX.1 behavior rather than the BSD -behavior. +restore the set of blocked signals; see @ref{Blocking Signals}, while +on @w{System V} they will not. POSIX does not specify the relation of +@code{setjmp} and @code{longjmp} to signal mask. The default in +@theglibc{} is the BSD behavior. The facilities in this section are declared in the header file @file{setjmp.h}. diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index 1ac8862ed2..3d7dfac198 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -399,7 +399,8 @@ start_thread (void *arg) the saved signal mask), so that is a false positive. */ DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overflow="); #endif - not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + not_first_call = __sigsetjmp ( + (struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf, 0); DIAG_POP_NEEDS_COMMENT; /* No previous handlers. NB: This must be done after setjmp since the diff --git a/setjmp/setjmp.h b/setjmp/setjmp.h index 3cdc2dfcfb..53edbba92b 100644 --- a/setjmp/setjmp.h +++ b/setjmp/setjmp.h @@ -44,11 +44,6 @@ extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROWNL Return 0. */ extern int _setjmp (struct __jmp_buf_tag __env[1]) __THROWNL; -/* Do not save the signal mask. This is equivalent to the `_setjmp' - BSD function. */ -#define setjmp(env) _setjmp (env) - - /* Jump to the environment saved in ENV, making the `setjmp' call there return VAL, or 1 if VAL is 0. */ extern void longjmp (struct __jmp_buf_tag __env[1], int __val) diff --git a/sysdeps/nptl/libc_start_call_main.h b/sysdeps/nptl/libc_start_call_main.h index a55e3df013..984e859550 100644 --- a/sysdeps/nptl/libc_start_call_main.h +++ b/sysdeps/nptl/libc_start_call_main.h @@ -41,7 +41,8 @@ __libc_start_call_main (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), the saved signal mask), so that is a false positive. */ DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overflow="); #endif - not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + not_first_call = __sigsetjmp ( + (struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf, 0); DIAG_POP_NEEDS_COMMENT; if (__glibc_likely (! not_first_call)) { From patchwork Mon Jul 31 17:19:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 1815197 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=Lm3ljLdT; dkim-atps=neutral Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RF4jc2rn1z20G3 for ; Tue, 1 Aug 2023 03:19:32 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 36D703857838 for ; Mon, 31 Jul 2023 17:19:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 36D703857838 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1690823970; bh=sDp+vq0k2NawskRbdBovmfUSfq0LEWMa+/0ukFs09Z8=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=Lm3ljLdTTIl9f9vs8W4VsFLuqAIstPftJuOq51bMaFIPkkvhsTaljKfN10aNVw789 UceRS/78HWzzQO5gKDhhPA6llcPsCTXZ3l7dsD6p3BM2nw3EYZQphqXuJV+LGkPKvO lvzsfB0JXoFt4w7nlSLYw//n2/F8+d8BWQO3b94s= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-oo1-xc36.google.com (mail-oo1-xc36.google.com [IPv6:2607:f8b0:4864:20::c36]) by sourceware.org (Postfix) with ESMTPS id E1A503858C66 for ; Mon, 31 Jul 2023 17:19:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E1A503858C66 Received: by mail-oo1-xc36.google.com with SMTP id 006d021491bc7-565f2567422so3264957eaf.2 for ; Mon, 31 Jul 2023 10:19:10 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690823949; x=1691428749; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sDp+vq0k2NawskRbdBovmfUSfq0LEWMa+/0ukFs09Z8=; b=bMTATL/8axJePZDarQNu5uhz6fesGhl4ZafUITA/uoouB4jHft3nQlmRPVVQZvV/i/ SJS/Ffs3eMjRlTVCyaOrw+J2segvAbBMtgfgvuEbXViyTO2QCaJxLR7cTkbFzzsPKhrH PyiEw9e3xcnjSUvcEGzbNbDQew+GRs44mf4/JOWibk7IRAjj16lba5fwbyZNe1BslHE8 2C3BXRk6Kb1FHLtD926pgIXazWJ9AyivXaLAjeocpw1xH2HvO69U+yNhnMupXgSWA4mX +BFI7GLM/6OfoOrT23sqPYWpAN3aPUptYHiBQuBejwIpyvxyga0Dkd31jj+HAN82XLnh l0OA== X-Gm-Message-State: ABy/qLbhc9pHIppzZ/A+mu/zn6UhRZjAvcB5LBsDGf2ppON5HtF2Ua4z gjmfVUcJw+qeO1NiuwO0oJAiV3UO0LkezXZLg9+Cvw== X-Google-Smtp-Source: APBJJlFc/0/KjJ0zDcayUQ+myUPIehQfch+YGdg63v3USRj76bikeq84kHpoeWzNj5aOGrVEvXvTdQ== X-Received: by 2002:a05:6808:2a59:b0:3a7:17b6:3501 with SMTP id fa25-20020a0568082a5900b003a717b63501mr6484124oib.23.1690823949151; Mon, 31 Jul 2023 10:19:09 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:440b:68be:64f1:9a6f:2423]) by smtp.gmail.com with ESMTPSA id k16-20020a05680808d000b003a724566afdsm1560047oij.20.2023.07.31.10.19.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Jul 2023 10:19:08 -0700 (PDT) To: libc-alpha@sourceware.org, Carlos O'Donell Subject: [PATCH 2/2] stdlib: Make abort AS-safe (BZ 26275) Date: Mon, 31 Jul 2023 14:19:00 -0300 Message-Id: <20230731171900.4065501-3-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230731171900.4065501-1-adhemerval.zanella@linaro.org> References: <20230731171900.4065501-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" The recursive lock used on abort does not synchronize with new process creation (either by fork-like interfaces or posix_spawn ones), nor it is reinitialized after fork. Also, the SIGABRT unblock before raise shows another race-condition, where a fork or posix_spawn call by another thread just after the recursive lock release and before the SIGABRT raise might create programs with a non-expected signal mask. To fix the AS-safe, the raise is issues without changing the process signal mask, and an AS-safe lock is used if a SIGABRT is installed or the process is blocked or ignored. The the signal mask change removal, there is no need to use a recursive lock. The lock is also used on both _Fork and posix_spawn, to avoid the spawn process to see the abort handler as SIG_DFL. The fallback is also simplified, there is no nned to use a loop of ABORT_INSTRUCTION after _exit (if the syscall does not terminate the process, the system is really broken). Checked on x86_64-linux-gnu and aarch64-linux-gnu. --- include/stdlib.h | 4 + manual/startup.texi | 3 - nptl/pthread_kill.c | 11 ++ posix/fork.c | 2 + signal/sigaction.c | 21 +++- stdlib/abort.c | 128 ++++++++------------- sysdeps/generic/internal-signals.h | 24 ++++ sysdeps/htl/pthreadP.h | 2 + sysdeps/nptl/_Fork.c | 12 ++ sysdeps/nptl/pthreadP.h | 1 + sysdeps/unix/sysv/linux/internal-signals.h | 9 ++ sysdeps/unix/sysv/linux/spawni.c | 3 + 12 files changed, 132 insertions(+), 88 deletions(-) diff --git a/include/stdlib.h b/include/stdlib.h index 7deb8193d7..b87a37e7e2 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -75,6 +75,10 @@ libc_hidden_proto (__isoc23_strtoull_l) # define strtoull_l __isoc23_strtoull_l #endif +extern void __abort_fork_reset_child (void) attribute_hidden; +extern void __abort_lock_lock (void) attribute_hidden; +extern void __abort_lock_unlock (void) attribute_hidden; + libc_hidden_proto (exit) libc_hidden_proto (abort) libc_hidden_proto (getenv) diff --git a/manual/startup.texi b/manual/startup.texi index 9bf24123f5..236a480a74 100644 --- a/manual/startup.texi +++ b/manual/startup.texi @@ -993,9 +993,6 @@ for this function is in @file{stdlib.h}. @deftypefun void abort (void) @standards{ISO, stdlib.h} @safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}} -@c The implementation takes a recursive lock and attempts to support -@c calls from signal handlers, but if we're in the middle of flushing or -@c using streams, we may encounter them in inconsistent states. The @code{abort} function causes abnormal program termination. This does not execute cleanup functions registered with @code{atexit} or @code{on_exit}. diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c index 44e45a4e23..e3364fb5d1 100644 --- a/nptl/pthread_kill.c +++ b/nptl/pthread_kill.c @@ -69,6 +69,17 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) return ret; } +/* Send the signal SIGNO to the caller. Used by abort and called where the + signals are being already blocked and there is no need to synchronize with + exit_lock. */ +int +__pthread_raise_internal (int signo) +{ + struct pthread *pd = THREAD_SELF; + int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); + return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; +} + int __pthread_kill_internal (pthread_t threadid, int signo) { diff --git a/posix/fork.c b/posix/fork.c index b4aaa9fa6d..1640d0750c 100644 --- a/posix/fork.c +++ b/posix/fork.c @@ -84,6 +84,8 @@ __libc_fork (void) fork_system_setup_after_fork (); + call_function_static_weak (__abort_fork_reset_child); + /* Release malloc locks. */ call_function_static_weak (__malloc_fork_unlock_child); diff --git a/signal/sigaction.c b/signal/sigaction.c index 3a49597c61..0d1358d720 100644 --- a/signal/sigaction.c +++ b/signal/sigaction.c @@ -16,8 +16,9 @@ . */ #include -#include #include +#include +#include /* If ACT is not NULL, change the action for SIG to *ACT. If OACT is not NULL, put the old action for SIG in *OACT. */ @@ -30,7 +31,23 @@ __sigaction (int sig, const struct sigaction *act, struct sigaction *oact) return -1; } - return __libc_sigaction (sig, act, oact); + internal_sigset_t set; + + if (sig == SIGABRT) + { + internal_signal_block_all (&set); + __abort_lock_lock (); + } + + int r = __libc_sigaction (sig, act, oact); + + if (sig == SIGABRT) + { + __abort_lock_unlock (); + internal_signal_restore_set (&set); + } + + return r; } libc_hidden_def (__sigaction) weak_alias (__sigaction, sigaction) diff --git a/stdlib/abort.c b/stdlib/abort.c index 16a453459c..e19ad730cd 100644 --- a/stdlib/abort.c +++ b/stdlib/abort.c @@ -15,13 +15,11 @@ License along with the GNU C Library; if not, see . */ -#include #include -#include -#include -#include -#include #include +#include +#include +#include /* Try to get a machine dependent instruction which will make the program crash. This is used in case everything else fails. */ @@ -35,89 +33,53 @@ struct abort_msg_s *__abort_msg; libc_hidden_def (__abort_msg) -/* We must avoid to run in circles. Therefore we remember how far we - already got. */ -static int stage; +/* The lock is used to prevent multiple thread to change the SIGABRT + to SIG_IGN while abort tries to change to SIG_DFL, and to avoid + a new process to see a wrong disposition if there is a SIGABRT + handler installed. */ +__libc_lock_define_initialized (static, lock); -/* We should be prepared for multiple threads trying to run abort. */ -__libc_lock_define_initialized_recursive (static, lock); - - -/* Cause an abnormal program termination with core-dump. */ void -abort (void) +__abort_fork_reset_child (void) { - struct sigaction act; - - /* First acquire the lock. */ - __libc_lock_lock_recursive (lock); - - /* Now it's for sure we are alone. But recursive calls are possible. */ - - /* Unblock SIGABRT. */ - if (stage == 0) - { - ++stage; - internal_sigset_t sigs; - internal_sigemptyset (&sigs); - internal_sigaddset (&sigs, SIGABRT); - internal_sigprocmask (SIG_UNBLOCK, &sigs, NULL); - } - - /* Send signal which possibly calls a user handler. */ - if (stage == 1) - { - /* This stage is special: we must allow repeated calls of - `abort' when a user defined handler for SIGABRT is installed. - This is risky since the `raise' implementation might also - fail but I don't see another possibility. */ - int save_stage = stage; - - stage = 0; - __libc_lock_unlock_recursive (lock); - - raise (SIGABRT); - - __libc_lock_lock_recursive (lock); - stage = save_stage + 1; - } - - /* There was a handler installed. Now remove it. */ - if (stage == 2) - { - ++stage; - memset (&act, '\0', sizeof (struct sigaction)); - act.sa_handler = SIG_DFL; - __sigfillset (&act.sa_mask); - act.sa_flags = 0; - __sigaction (SIGABRT, &act, NULL); - } - - /* Try again. */ - if (stage == 3) - { - ++stage; - raise (SIGABRT); - } + __libc_lock_init (lock); +} - /* Now try to abort using the system specific command. */ - if (stage == 4) - { - ++stage; - ABORT_INSTRUCTION; - } +void +__abort_lock_lock (void) +{ + __libc_lock_lock (lock); +} - /* If we can't signal ourselves and the abort instruction failed, exit. */ - if (stage == 5) - { - ++stage; - _exit (127); - } +void +__abort_lock_unlock (void) +{ + __libc_lock_unlock (lock); +} - /* If even this fails try to use the provided instruction to crash - or otherwise make sure we never return. */ - while (1) - /* Try for ever and ever. */ - ABORT_INSTRUCTION; +/* Cause an abnormal program termination with core-dump. */ +_Noreturn void +abort (void) +{ + raise (SIGABRT); + + /* There is a SIGABRT handler installed and it returned, or SIGABRT was + blocked or ignored. In this case use a AS-safe lock to prevent sigaction + to change the signal disposition, reinstall the handle to abort the + process, and raise the signal again. */ + internal_signal_block_all (NULL); + __libc_lock_lock (lock); + + struct sigaction act = {.sa_handler = SIG_DFL, .sa_flags = 0 }; + __sigfillset (&act.sa_mask); + __libc_sigaction (SIGABRT, &act, NULL); + __pthread_raise_internal (SIGABRT); + internal_signal_unblock_signal (SIGABRT); + + /* This code should be unreachable, try the arch-specific code and the + syscall fallback. */ + ABORT_INSTRUCTION; + + _exit (127); } libc_hidden_def (abort) diff --git a/sysdeps/generic/internal-signals.h b/sysdeps/generic/internal-signals.h index e2e9f9fd49..1c0f7b2e6c 100644 --- a/sysdeps/generic/internal-signals.h +++ b/sysdeps/generic/internal-signals.h @@ -42,7 +42,31 @@ clear_internal_signals (sigset_t *set) typedef sigset_t internal_sigset_t; #define internal_sigemptyset(__s) __sigemptyset (__s) +#define internal_sigfillset(__s) __sigfillset (__s) #define internal_sigaddset(__s, __i) __sigaddset (__s, __i) #define internal_sigprocmask(__h, __s, __o) __sigprocmask (__h, __s, __o) +static inline void +internal_signal_block_all (internal_sigset_t *oset) +{ + internal_sigset_t set; + internal_sigfillset (&set); + internal_sigprocmask (SIG_BLOCK, &set, oset); +} + +static inline void +internal_signal_restore_set (const internal_sigset_t *set) +{ + internal_sigprocmask (SIG_SETMASK, set, NULL); +} + +static inline void +internal_signal_unblock_signal (int sig) +{ + internal_sigset_t set; + internal_sigemptyset (&set); + internal_sigaddset (&set, sig); + internal_sigprocmask (SIG_UNBLOCK, &set, NULL); +} + #endif /* __INTERNAL_SIGNALS_H */ diff --git a/sysdeps/htl/pthreadP.h b/sysdeps/htl/pthreadP.h index 3f052f0e53..7410261d1a 100644 --- a/sysdeps/htl/pthreadP.h +++ b/sysdeps/htl/pthreadP.h @@ -92,6 +92,8 @@ int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, int __pthread_attr_getstack (const pthread_attr_t *, void **, size_t *); void __pthread_testcancel (void); +#define __pthread_raise_internal(__sig) raise (__sig) + libc_hidden_proto (__pthread_self) #if IS_IN (libpthread) diff --git a/sysdeps/nptl/_Fork.c b/sysdeps/nptl/_Fork.c index f8322ae557..f6da952ce0 100644 --- a/sysdeps/nptl/_Fork.c +++ b/sysdeps/nptl/_Fork.c @@ -17,11 +17,19 @@ . */ #include +#include #include pid_t _Fork (void) { + /* The lock acquisition needs to be AS-safe to avoid deadlock if _Fork is + called from the signal handler that has interrupted fork itself. */ + internal_sigset_t set; + + internal_signal_block_all (&set); + __abort_lock_lock (); + pid_t pid = arch_fork (&THREAD_SELF->tid); if (pid == 0) { @@ -44,6 +52,10 @@ _Fork (void) INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head, sizeof (struct robust_list_head)); } + + __abort_lock_unlock (); + internal_signal_restore_set (&set); + return pid; } libc_hidden_def (_Fork) diff --git a/sysdeps/nptl/pthreadP.h b/sysdeps/nptl/pthreadP.h index 54f9198681..6cc675c5a5 100644 --- a/sysdeps/nptl/pthreadP.h +++ b/sysdeps/nptl/pthreadP.h @@ -508,6 +508,7 @@ libc_hidden_proto (__pthread_kill) extern int __pthread_cancel (pthread_t th); extern int __pthread_kill_internal (pthread_t threadid, int signo) attribute_hidden; +extern int __pthread_raise_internal (int signo) attribute_hidden; extern void __pthread_exit (void *value) __attribute__ ((__noreturn__)); libc_hidden_proto (__pthread_exit) extern int __pthread_join (pthread_t threadid, void **thread_return); diff --git a/sysdeps/unix/sysv/linux/internal-signals.h b/sysdeps/unix/sysv/linux/internal-signals.h index 43c3c0b4a0..c58f568dda 100644 --- a/sysdeps/unix/sysv/linux/internal-signals.h +++ b/sysdeps/unix/sysv/linux/internal-signals.h @@ -90,6 +90,15 @@ internal_signal_restore_set (const internal_sigset_t *set) __NSIG_BYTES); } +static inline void +internal_signal_unblock_signal (int sig) +{ + internal_sigset_t set; + internal_sigemptyset (&set); + internal_sigaddset (&set, sig); + INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &set, NULL, + __NSIG_BYTES); +} /* It is used on timer_create code directly on sigwaitinfo call, so it can not use the internal_sigset_t definitions. */ diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index ec687cb423..3ef07ec633 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -371,6 +371,7 @@ __spawnix (pid_t * pid, const char *file, args.xflags = xflags; internal_signal_block_all (&args.oldmask); + __abort_lock_lock (); /* The clone flags used will create a new child that will run in the same memory space (CLONE_VM) and the execution of calling thread will be @@ -402,6 +403,8 @@ __spawnix (pid_t * pid, const char *file, &args); } + __abort_lock_unlock (); + /* It needs to collect the case where the auxiliary process was created but failed to execute the file (due either any preparation step or for execve itself). */