NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/58268: execve() discards pending signal



>Number:         58268
>Category:       kern
>Synopsis:       execve() discards pending signal
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon May 20 04:30:00 +0000 2024
>Originator:     Noah Misch
>Release:        9.2, 9.4, 10.0
>Organization:
>Environment:
NetBSD  10.0 NetBSD 10.0 (GENERIC) #0: Thu Mar 28 08:33:33 UTC 2024  mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html says the
new process inherits "pending signal".  Per the below test program, a signal
pending before execve() is neither delivered nor pending after execve().  The
test program observed this in NetBSD 9.2, 9.4 and 10.0.  The other operating
systems I tested keep the signal pending; the test program header comment lists
them.

[non-essential background info] I discovered this in the context of
https://github.com/cpan-authors/IPC-Run/issues/175, where an IPC::Run test case
can make kill(KID, SIGTERM) overlap KID running exec().  The IPC::Run test never
runs kill() before exec(), always during exec() or after exec().  Hence, it's
different from the below C program, which makes the signal pending before
exec().  The IPC::Run test case was stable on NetBSD until NetBSD 10.0.
Starting with NetBSD 10.0, the IPC::Run SIGTERM is usually lost.  Perhaps NetBSD
10.0 expanded the ability of actions to interrupt exec().  That's fine.
>How-To-Repeat:
/*
 * Return value:
 * 1 if sigprocmask(SIG_UNBLOCK) returns w/ SIGTERM pending
 * 2 if sigprocmask(SIG_UNBLOCK) returns w/ SIGTERM *not* pending
 * 90 if exec fails
 *
 * AIX 7300-01-02-2320: returns 1 always.  Compiling with -DREBLOCK makes it die
 * to SIGTERM always.
 *
 * Same as AIX:
 * Darwin 21.6.0
 * FreeBSD 14.0-release-p6
 * Linux 6.7.12-amd64
 * OpenBSD 7.5
 * Solaris 11.4.68.164.2
 *
 * NetBSD 10.0, 9.4, 9.2: returns 2 always.
 *
 * Linux 3.10.0-1160.99.1.el7.x86_64: Dies to SIGTERM about half the time,
 * returning 1 the other half.  Compiling with -DREBLOCK makes it die to SIGTERM
 * always.
 */
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    sigset_t set;

    if (argc == 1)
    {
	char *cmd[] = { argv[0], "anything", (char *)0 };

	sigemptyset(&set);
	sigaddset(&set, SIGTERM);
	sigprocmask(SIG_BLOCK, &set, NULL);
	raise(SIGTERM);

	execv(argv[0], cmd);
	return 90;
    }
    else
    {
	char msg[] = "reached write()\n";

#if REBLOCK
	sigemptyset(&set);
	sigaddset(&set, SIGTERM);
	sigprocmask(SIG_BLOCK, &set, NULL);
#endif
	write(2, msg, sizeof(msg) - 1);
	sigprocmask(SIG_UNBLOCK, &set, NULL);
	sigpending(&set);
	return sigismember(&set, SIGTERM) ? 1 : 2;
    }
}
>Fix:
not known



Home | Main Index | Thread Index | Old Index