Module Name:    src
Committed By:   riastradh
Date:           Thu Mar 13 01:27:27 UTC 2025

Modified Files:
        src/distrib/sets/lists/debug: mi
        src/distrib/sets/lists/tests: mi
        src/tests/lib/libc/gen: Makefile
        src/tests/lib/libc/gen/execve: t_execve.c
        src/tests/lib/libc/gen/posix_spawn: t_spawn.c
Added Files:
        src/tests/lib/libc/gen: h_execsig.c

Log Message:
execve(2), posix_spawn(2): Add test case for an embarrassing bug.

PR kern/58091: after fork/execve or posix_spawn, parent kill(child,
SIGTERM) has race condition making it unreliable


To generate a diff of this commit:
cvs rdiff -u -r1.468 -r1.469 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.1360 -r1.1361 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.56 -r1.57 src/tests/lib/libc/gen/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/gen/h_execsig.c
cvs rdiff -u -r1.2 -r1.3 src/tests/lib/libc/gen/execve/t_execve.c
cvs rdiff -u -r1.8 -r1.9 src/tests/lib/libc/gen/posix_spawn/t_spawn.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.468 src/distrib/sets/lists/debug/mi:1.469
--- src/distrib/sets/lists/debug/mi:1.468	Tue Mar 11 13:56:48 2025
+++ src/distrib/sets/lists/debug/mi	Thu Mar 13 01:27:27 2025
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.468 2025/03/11 13:56:48 brad Exp $
+# $NetBSD: mi,v 1.469 2025/03/13 01:27:27 riastradh Exp $
 #
 ./etc/mtree/set.debug                           comp-sys-root
 ./usr/lib					comp-sys-usr		compatdir
@@ -2016,6 +2016,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/db/t_db_hash_seq.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/gen/exect/t_exect.debug		tests-kernel-obsolete	obsolete
 ./usr/libdata/debug/usr/tests/lib/libc/gen/execve/t_execve.debug	tests-kernel-tests	debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/gen/h_execsig.debug		tests-kernel-tests	debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/gen/posix_spawn/h_fileactions.debug	tests-kernel-tests	debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/gen/posix_spawn/h_spawn.debug		tests-kernel-tests	debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/gen/posix_spawn/h_spawnattr.debug	tests-kernel-tests	debug,atf,compattestfile

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.1360 src/distrib/sets/lists/tests/mi:1.1361
--- src/distrib/sets/lists/tests/mi:1.1360	Sun Mar  2 16:35:40 2025
+++ src/distrib/sets/lists/tests/mi	Thu Mar 13 01:27:27 2025
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1360 2025/03/02 16:35:40 riastradh Exp $
+# $NetBSD: mi,v 1.1361 2025/03/13 01:27:27 riastradh Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -2991,6 +2991,7 @@
 ./usr/tests/lib/libc/gen/execve/Atffile			tests-kernel-tests	compattestfile,atf
 ./usr/tests/lib/libc/gen/execve/Kyuafile		tests-kernel-tests	compattestfile,atf,kyua
 ./usr/tests/lib/libc/gen/execve/t_execve		tests-kernel-tests	compattestfile,atf
+./usr/tests/lib/libc/gen/h_execsig			tests-kernel-tests	compattestfile,atf
 ./usr/tests/lib/libc/gen/posix_spawn			tests-kernel-tests	compattestfile,atf
 ./usr/tests/lib/libc/gen/posix_spawn/Atffile		tests-kernel-tests	compattestfile,atf
 ./usr/tests/lib/libc/gen/posix_spawn/Kyuafile		tests-kernel-tests	compattestfile,atf,kyua

Index: src/tests/lib/libc/gen/Makefile
diff -u src/tests/lib/libc/gen/Makefile:1.56 src/tests/lib/libc/gen/Makefile:1.57
--- src/tests/lib/libc/gen/Makefile:1.56	Tue Aug 27 13:43:02 2024
+++ src/tests/lib/libc/gen/Makefile	Thu Mar 13 01:27:27 2025
@@ -1,8 +1,11 @@
-# $NetBSD: Makefile,v 1.56 2024/08/27 13:43:02 riastradh Exp $
+# $NetBSD: Makefile,v 1.57 2025/03/13 01:27:27 riastradh Exp $
+
+NOMAN=		# defined
 
 .include <bsd.own.mk>
 
 TESTSDIR=	${TESTSBASE}/lib/libc/gen
+BINDIR=		${TESTSDIR}
 
 TESTS_SUBDIRS+=	execve
 TESTS_SUBDIRS+=	posix_spawn
@@ -41,6 +44,8 @@ TESTS_C+=	t_time
 TESTS_C+=	t_ttyname
 TESTS_C+=	t_vis
 
+PROGS+=		h_execsig
+
 .if ${MKSANITIZER:Uno} != "yes" && ${MKLIBCSANITIZER:Uno} != "yes"
 COPTS.t_siginfo.c+=	-DENABLE_TESTS
 .endif

Index: src/tests/lib/libc/gen/execve/t_execve.c
diff -u src/tests/lib/libc/gen/execve/t_execve.c:1.2 src/tests/lib/libc/gen/execve/t_execve.c:1.3
--- src/tests/lib/libc/gen/execve/t_execve.c:1.2	Sat Sep 12 15:21:33 2015
+++ src/tests/lib/libc/gen/execve/t_execve.c	Thu Mar 13 01:27:27 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_execve.c,v 1.2 2015/09/12 15:21:33 christos Exp $	*/
+/*	$NetBSD: t_execve.c,v 1.3 2025/03/13 01:27:27 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -26,21 +26,29 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_execve.c,v 1.3 2025/03/13 01:27:27 riastradh Exp $");
+
+#include <sys/wait.h>
+
 #include <atf-c.h>
 
 #include <errno.h>
+#include <limits.h>
+#include <signal.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <time.h>
 
-ATF_TC(t_execve_null);
+#include "h_macros.h"
 
+ATF_TC(t_execve_null);
 ATF_TC_HEAD(t_execve_null, tc)
 {
 	atf_tc_set_md_var(tc, "descr",
 	    "Tests an empty execve(2) executing");
 }
-
 ATF_TC_BODY(t_execve_null, tc)
 {
 	int err;
@@ -51,9 +59,58 @@ ATF_TC_BODY(t_execve_null, tc)
 	    "wrong error returned %d instead of %d", errno, EFAULT);
 }
 
+ATF_TC(t_execve_sig);
+ATF_TC_HEAD(t_execve_sig, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Checks that execve does not drop pending signals");
+}
+ATF_TC_BODY(t_execve_sig, tc)
+{
+	const char *srcdir = atf_tc_get_config_var(tc, "srcdir");
+	char h_execsig[PATH_MAX];
+	time_t start;
+
+	snprintf(h_execsig, sizeof(h_execsig), "%s/../h_execsig", srcdir);
+	REQUIRE_LIBC(signal(SIGPIPE, SIG_IGN), SIG_ERR);
+
+	atf_tc_expect_fail("PR kern/580911: after fork/execve or posix_spawn,"
+	    " parent kill(child, SIGTERM) has race condition"
+	    " making it unreliable");
+
+	for (start = time(NULL); time(NULL) - start <= 10;) {
+		int fd[2];
+		char *const argv[] = {h_execsig, NULL};
+		pid_t pid;
+		int status;
+
+		RL(pipe(fd));
+		RL(pid = vfork());
+		if (pid == 0) {
+			if (dup2(fd[0], STDIN_FILENO) == -1)
+				_exit(1);
+			(void)execve(argv[0], argv, NULL);
+			_exit(2);
+		}
+		RL(close(fd[0]));
+		RL(kill(pid, SIGTERM));
+		if (write(fd[1], (char[]){0}, 1) == -1 && errno != EPIPE)
+			atf_tc_fail("write failed: %s", strerror(errno));
+		RL(waitpid(pid, &status, 0));
+		ATF_REQUIRE_MSG(WIFSIGNALED(status),
+		    "child exited with status 0x%x", status);
+		ATF_REQUIRE_EQ_MSG(WTERMSIG(status), SIGTERM,
+		    "child exited on signal %d (%s)",
+		    WTERMSIG(status), strsignal(WTERMSIG(status)));
+		RL(close(fd[1]));
+	}
+}
+
 ATF_TP_ADD_TCS(tp)
 {
+
 	ATF_TP_ADD_TC(tp, t_execve_null);
+	ATF_TP_ADD_TC(tp, t_execve_sig);
 
 	return atf_no_error();
 }

Index: src/tests/lib/libc/gen/posix_spawn/t_spawn.c
diff -u src/tests/lib/libc/gen/posix_spawn/t_spawn.c:1.8 src/tests/lib/libc/gen/posix_spawn/t_spawn.c:1.9
--- src/tests/lib/libc/gen/posix_spawn/t_spawn.c:1.8	Tue May 31 11:22:34 2022
+++ src/tests/lib/libc/gen/posix_spawn/t_spawn.c	Thu Mar 13 01:27:27 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: t_spawn.c,v 1.8 2022/05/31 11:22:34 andvar Exp $ */
+/* $NetBSD: t_spawn.c,v 1.9 2025/03/13 01:27:27 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2012, 2021 The NetBSD Foundation, Inc.
@@ -29,27 +29,31 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_spawn.c,v 1.8 2022/05/31 11:22:34 andvar Exp $");
+__RCSID("$NetBSD: t_spawn.c,v 1.9 2025/03/13 01:27:27 riastradh Exp $");
 
 #include <atf-c.h>
 
 #include <sys/fcntl.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <sys/stat.h>
 
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
 #include <spawn.h>
-#include <string.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <fcntl.h>
+#include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "fa_spawn_utils.h"
-
+#include "h_macros.h"
 
 static void check_success(const char *, int, ...);
 
@@ -583,6 +587,47 @@ ATF_TC_BODY(t_spawn_fchdir_closed, tc)
 	posix_spawnattr_destroy(&attr);
 }
 
+ATF_TC(t_spawn_sig);
+ATF_TC_HEAD(t_spawn_sig, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Checks that posix_spawn does not drop pending signals");
+}
+ATF_TC_BODY(t_spawn_sig, tc)
+{
+	const char *srcdir = atf_tc_get_config_var(tc, "srcdir");
+	char h_execsig[PATH_MAX];
+	time_t start;
+
+	snprintf(h_execsig, sizeof(h_execsig), "%s/../h_execsig", srcdir);
+	REQUIRE_LIBC(signal(SIGPIPE, SIG_IGN), SIG_ERR);
+
+	atf_tc_expect_fail("PR kern/580911: after fork/execve or posix_spawn,"
+	    " parent kill(child, SIGTERM) has race condition"
+	    " making it unreliable");
+
+	for (start = time(NULL); time(NULL) - start <= 10;) {
+		int fd[2];
+		char *const argv[] = {h_execsig, NULL};
+		pid_t pid;
+		int status;
+
+		RL(pipe(fd));
+		RZ(posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL));
+		RL(close(fd[0]));
+		RL(kill(pid, SIGTERM));
+		if (write(fd[1], (char[]){0}, 1) == -1 && errno != EPIPE)
+			atf_tc_fail("write failed: %s", strerror(errno));
+		RL(waitpid(pid, &status, 0));
+		ATF_REQUIRE_MSG(WIFSIGNALED(status),
+		    "child exited with status 0x%x", status);
+		ATF_REQUIRE_EQ_MSG(WTERMSIG(status), SIGTERM,
+		    "child exited on signal %d (%s)",
+		    WTERMSIG(status), strsignal(WTERMSIG(status)));
+		RL(close(fd[1]));
+	}
+}
+
 #undef CHDIR
 #undef FCHDIR
 #undef CHDIRPATH
@@ -607,6 +652,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, t_spawn_fchdir_file);
 	ATF_TP_ADD_TC(tp, t_spawn_fchdir_neg_fd);
 	ATF_TP_ADD_TC(tp, t_spawn_fchdir_closed);
+	ATF_TP_ADD_TC(tp, t_spawn_sig);
 
 	return atf_no_error();
 }

Added files:

Index: src/tests/lib/libc/gen/h_execsig.c
diff -u /dev/null src/tests/lib/libc/gen/h_execsig.c:1.1
--- /dev/null	Thu Mar 13 01:27:28 2025
+++ src/tests/lib/libc/gen/h_execsig.c	Thu Mar 13 01:27:27 2025
@@ -0,0 +1,55 @@
+/*	$NetBSD: h_execsig.c,v 1.1 2025/03/13 01:27:27 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2025 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: h_execsig.c,v 1.1 2025/03/13 01:27:27 riastradh Exp $");
+
+/*
+ * Helper program for testing signal delivery during execve(2) and
+ * posix_spawn(2).  The caller will:
+ *
+ * 1. fork and exec, or spawn
+ * 2. kill the child
+ * 3. write a byte to be read from the child's stdin
+ *
+ * Since the caller issues syscalls in that order, the signal should be
+ * delivered to the child first, and it should be interrupted by a
+ * signal before it returnsa byte from read(2).
+ */
+
+#include <err.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+
+	if (read(STDIN_FILENO, (char[]){0}, 1) == -1)
+		err(1, "read");
+	return 0;
+}

Reply via email to