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;
+}