From nobody Wed Mar 4 14:45:06 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fQwSS366tz6TbJT for ; Wed, 04 Mar 2026 14:45:12 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fQwSS0VVrz3bRL for ; Wed, 04 Mar 2026 14:45:12 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772635512; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=G7wg1Nyv0HIWF5rCufqaBQuolsK9vHtMhhwRU53HtwU=; b=UdI9fXLBmMXCRBLr9Kcqjt6hXLgV13rM+tu9wTNb7bJBmjSzrRzGJg0o8E42rP1j/0+OwN M1pxLt+0xU62hB9n3eSZNsJ2m59DPA7Sadw0Uwwxz4bPx2DxzEjLKTpYogzhtj9gtx4ENG rRH40sRVELkVTn8CRrZTJ5E+OLUOJyJuOx0JXgtd0jQVGvZF1n9KLkKUr0Y4Sz/3/vDjfv y+9xsFjHKShrkLsoIkVrwKDvwHcIsILwDP9xbjQ8mySW3+P7yspx7CPrHo50VOU6bGkNOk qWXNwj1AxjmGZEMVqEt51LShR0weYThQYt4bEpflsgtoCSiSb5sGGjGP5D4D0g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1772635512; a=rsa-sha256; cv=none; b=QWKqhQEe17u9Zi9qi0YzZu9eRDKtrMSA33Ma6uHNEl7KdXSqm4TLpk77yIAyMeGD2PckH1 46x1+ErzQmDlip3YgZJ9J0QXdU4WNjJGJ5m0+FT/OlJ6263sgTKuEbNhmRv0UWWrMTGxmH DDhAprMjPF3lmtoWonnxXeeJf5kD7GotLCCfgIyMSuIHxzKSqjaLnvRfB+hwDGBBmggFiQ IGZ31bmLTRm4RUc49UGUad/paDcbLHi0SdBjoOv4FqkzUbUE74AKB2pJosqTsggeX1+jOr irCFJecXaIme3r8qAd3+qwX0rPYkv7KDNMpAAceLuUcVkmD+7n1MSXLgH9yp4w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772635512; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=G7wg1Nyv0HIWF5rCufqaBQuolsK9vHtMhhwRU53HtwU=; b=RdoCno0yy1r1bdE4ACwRmAwylaQAREgk3m8AqbodR5XrTmDogg194/jbuWko/e3cTtnHMj bzqkagJMk5JKzQAmndQgsdCM8ogwaDJcn8D/0hAuh6shCHyvau2HSoqsWwi3TtwH7BRB9c YL+Qc2soQt/i+hTPwhIX+L+vBIq8+L4U86//TWFwzGkHTYieymQeVLw8ZBJySLXHAw2Jv6 24C1MJfXU8tB6aZ0Tr9VdJo0wxp5cLoTMstcGvwc2z+ljD/MUzdpK5/Oleh3lwtxuq58vq HmASJl2OTdncQJfN0KCEKRH6NUl1vfSiLu2V8ih1mzIe5IL9kOXSKLJWfseD7g== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fQwSS03kMzw4J for ; Wed, 04 Mar 2026 14:45:12 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 26259 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 04 Mar 2026 14:45:06 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav Subject: git: 1ea0da88d134 - stable/15 - system(3): Improve signal handling List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 1ea0da88d134918e1b0a0e0e13809b27e43b797f Auto-Submitted: auto-generated Date: Wed, 04 Mar 2026 14:45:06 +0000 Message-Id: <69a84572.26259.11b1d4bd@gitrepo.freebsd.org> The branch stable/15 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=1ea0da88d134918e1b0a0e0e13809b27e43b797f commit 1ea0da88d134918e1b0a0e0e13809b27e43b797f Author: Dag-Erling Smørgrav AuthorDate: 2026-02-25 21:12:21 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2026-03-04 14:44:59 +0000 system(3): Improve signal handling Ignore SIGINT and SIGQUIT and block SIGCHLD, as POSIX requires. To deal with the concurrency problem described in POSIX, we keep track of the count of concurrent invocations. We ignore and block signals only when the counter was zero before we incremented it, and restore them only when the counter reaches zero after we decrement it. Note that this does not address the issue of thread cancellation. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: bnovkov, sef, kevans Differential Revision: https://reviews.freebsd.org/D55471 (cherry picked from commit 6e589e6e8e64793adb437c561ec084dbb6ad1ced) --- lib/libc/stdlib/system.c | 116 +++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c index b581a6ec3b14..17dd63eb52f9 100644 --- a/lib/libc/stdlib/system.c +++ b/lib/libc/stdlib/system.c @@ -32,21 +32,22 @@ #include "namespace.h" #include #include + +#include +#include #include -#include #include +#include #include #include -#include -#include #include "un-namespace.h" #include "libc_private.h" +#include "spinlock.h" #pragma weak system int system(const char *command) { - return (((int (*)(const char *)) __libc_interposing[INTERPOS_system])(command)); } @@ -54,54 +55,83 @@ system(const char *command) int __libc_system(const char *command) { - pid_t pid, savedpid; - int pstat; - struct sigaction ign, intact, quitact; - sigset_t newsigblock, oldsigblock; + static spinlock_t lock = _SPINLOCK_INITIALIZER; + static volatile unsigned long concurrent; + static struct sigaction ointact, oquitact; + struct sigaction ign; + sigset_t sigblock, osigblock; + int pstat = -1, serrno = 0; + pid_t pid; - if (!command) /* just checking... */ - return(1); + if (command == NULL) /* just checking... */ + return (1); - (void)sigemptyset(&newsigblock); - (void)sigaddset(&newsigblock, SIGCHLD); - (void)sigaddset(&newsigblock, SIGINT); - (void)sigaddset(&newsigblock, SIGQUIT); - (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); - switch(pid = vfork()) { /* - * In the child, use unwrapped syscalls. libthr is in - * undefined state after vfork(). + * If we are the first concurrent instance, ignore SIGINT and + * SIGQUIT. Block SIGCHLD regardless of concurrency, since on + * FreeBSD, sigprocmask() is equivalent to pthread_sigmask(). */ - case -1: /* error */ - (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - return (-1); - case 0: /* child */ + if (__isthreaded) + _SPINLOCK(&lock); + if (concurrent++ == 0) { + memset(&ign, 0, sizeof(ign)); + ign.sa_handler = SIG_IGN; + sigemptyset(&ign.sa_mask); + (void)__libc_sigaction(SIGINT, &ign, &ointact); + (void)__libc_sigaction(SIGQUIT, &ign, &oquitact); + } + sigemptyset(&sigblock); + sigaddset(&sigblock, SIGCHLD); + (void)__libc_sigprocmask(SIG_BLOCK, &sigblock, &osigblock); + if (__isthreaded) + _SPINUNLOCK(&lock); + + /* + * Fork the child process. + */ + if ((pid = fork()) < 0) { /* error */ + serrno = errno; + } else if (pid == 0) { /* child */ /* - * Restore original signal dispositions and exec the command. + * Restore original signal dispositions. */ - (void)__sys_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); + (void)__libc_sigaction(SIGINT, &ointact, NULL); + (void)__libc_sigaction(SIGQUIT, &oquitact, NULL); + (void)__sys_sigprocmask(SIG_SETMASK, &osigblock, NULL); + /* + * Exec the command. + */ + execl(_PATH_BSHELL, "sh", "-c", command, NULL); _exit(127); + } else { /* parent */ + /* + * Wait for the child to terminate. + */ + while (_wait4(pid, &pstat, 0, NULL) < 0) { + if (errno != EINTR) { + serrno = errno; + break; + } + } } - /* - * If we are running means that the child has either completed - * its execve, or has failed. - * Block SIGINT/QUIT because sh -c handles it and wait for - * it to clean up. + + /* + * If we are the last concurrent instance, restore original signal + * dispositions. Unblock SIGCHLD, unless it was already blocked. */ - memset(&ign, 0, sizeof(ign)); - ign.sa_handler = SIG_IGN; - (void)sigemptyset(&ign.sa_mask); - (void)__libc_sigaction(SIGINT, &ign, &intact); - (void)__libc_sigaction(SIGQUIT, &ign, &quitact); - savedpid = pid; - do { - pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0); - } while (pid == -1 && errno == EINTR); - (void)__libc_sigaction(SIGINT, &intact, NULL); - (void)__libc_sigaction(SIGQUIT, &quitact, NULL); - (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - return (pid == -1 ? -1 : pstat); + if (__isthreaded) + _SPINLOCK(&lock); + if (--concurrent == 0) { + (void)__libc_sigaction(SIGINT, &ointact, NULL); + (void)__libc_sigaction(SIGQUIT, &oquitact, NULL); + } + if (!sigismember(&osigblock, SIGCHLD)) + (void)__libc_sigprocmask(SIG_UNBLOCK, &sigblock, NULL); + if (__isthreaded) + _SPINUNLOCK(&lock); + if (serrno != 0) + errno = serrno; + return (pstat); } __weak_reference(__libc_system, __system);