NetBSD-Bugs archive

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

kern/57260: open(2) fails to restart on signal with SA_RESTART



>Number:         57260
>Category:       kern
>Synopsis:       open(2) fails to restart on signal with SA_RESTART
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Mar 05 14:00:00 +0000 2023
>Originator:     Taylor R Campbell
>Release:        current
>Organization:
The NetBS<Interrupted system call>
>Environment:
only one environment to use, can't restart on signal of pending climate catastrophe
>Description:
open(2) changes an ERESTART return value produced internally by opening a vnode into EINTR, as if a signal had been delivered without SA_RESTART, so that the system call will return immediately rather than restart:

https://nxr.netbsd.org/xref/src/sys/kern/vfs_syscalls.c?r=1.556#1756

   1752 	error = vn_open(dvp, pb, TRYEMULROOT, flags, cmode,
   1753 	    &vp, &dupfd_move, &dupfd);
   1754 	if (error != 0) {
   1755 		fd_abort(p, fp, indx);
   1756 		if (error == ERESTART)
   1757 			error = EINTR;
   1758 		return error;
   1759 	}

This breaks the POSIX rule about SA_RESTART -- from https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html:

NAME
    sigaction - examine and change a signal action
...
DESCRIPTION
...
    SA_RESTART
        This flag affects the behavior of interruptible functions; that is, those specified to fail with errno set to [EINTR].  If set, and a function specified as interruptible is interrupted by this signal, the function shall restart and shall not fail with [EINTR] unless otherwise specified.  If an interruptible function which uses a timeout is restarted, the duration of the timeout following the restart is set to an unspecified value that does not exceed the original timeout value.  If the flag is not set, interruptible functions interrupted by this signal shall fail with errno set to [EINTR].

From https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html:

NAME
    open, openat - open file
...
ERRORS
    These functions fail if:
    ...
    [EINTR]
        A signal was caught during open().

Nothing in the description of open specifies otherwise about restartable system calls.
>How-To-Repeat:
The following program should print SIGALRM and then hang indefinitely, but instead it fails with interrupted system call:

#include <sys/stat.h>

#include <err.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

static void
on_alarm(int sig)
{
	const char msg[] = "SIGALRM\n";

	(void)write(STDERR_FILENO, msg, strlen(msg));
}

int
main(void)
{
	struct sigaction sa;
	int fd;

	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = on_alarm;
	(void)sigfillset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;
	if (sigaction(SIGALRM, &sa, NULL) == -1)
		err(1, "sigaction");

	if (mkfifo("fifo", 0600) == -1)
		err(1, "mkfifo");
	alarm(1);
	fd = open("fifo", O_RDONLY);
	if (fd == -1)
		err(1, "open");
	errx(1, "open returned %d", fd);
}

>Fix:
Delete the lines mapping EINTR to ERESTART in do_open in vfs_syscalls.c.



Home | Main Index | Thread Index | Old Index