summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2020-06-10 01:30:37 +0000
committerKyle Evans <kevans@FreeBSD.org>2020-06-10 01:30:37 +0000
commit301cb491ea417e54c29e63ebe00afbc8de47cd1f (patch)
treef537b25e28fe530e189543e98c350281e78db50a
parent1138b87ae640bb1ac22549ddb0490ebed692070c (diff)
Notes
-rw-r--r--lib/libc/gen/exec.c22
-rw-r--r--lib/libc/tests/gen/Makefile9
-rw-r--r--lib/libc/tests/gen/posix_spawn_test.c39
3 files changed, 66 insertions, 4 deletions
diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c
index 799a89d5c7e3..76c0454600eb 100644
--- a/lib/libc/gen/exec.c
+++ b/lib/libc/gen/exec.c
@@ -215,14 +215,28 @@ retry: (void)_execve(bp, argv, envp);
case ENOEXEC:
for (cnt = 0; argv[cnt]; ++cnt)
;
- memp = alloca((cnt + 2) * sizeof(char *));
+
+ /*
+ * cnt may be 0 above; always allocate at least
+ * 3 entries so that we can at least fit "sh", bp, and
+ * the NULL terminator. We can rely on cnt to take into
+ * account the NULL terminator in all other scenarios,
+ * as we drop argv[0].
+ */
+ memp = alloca(MAX(3, cnt + 2) * sizeof(char *));
if (memp == NULL) {
/* errno = ENOMEM; XXX override ENOEXEC? */
goto done;
}
- memp[0] = "sh";
- memp[1] = bp;
- bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+ if (cnt > 0) {
+ memp[0] = argv[0];
+ memp[1] = bp;
+ bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+ } else {
+ memp[0] = "sh";
+ memp[1] = bp;
+ memp[2] = NULL;
+ }
(void)_execve(_PATH_BSHELL,
__DECONST(char **, memp), envp);
goto done;
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
index 182966aadb26..74a245779d1b 100644
--- a/lib/libc/tests/gen/Makefile
+++ b/lib/libc/tests/gen/Makefile
@@ -24,6 +24,15 @@ ATF_TESTS_C+= wordexp_test
# TODO: t_siginfo (fixes require further inspection)
# TODO: t_sethostname_test (consistently screws up the hostname)
+FILESGROUPS+= posix_spawn_test_FILES
+
+posix_spawn_test_FILES= spawnp_enoexec.sh
+posix_spawn_test_FILESDIR= ${TESTSDIR}
+posix_spawn_test_FILESMODE= 0755
+posix_spawn_test_FILESOWN= root
+posix_spawn_test_FILESGRP= wheel
+posix_spawn_test_FILESPACKAGE= ${PACKAGE}
+
CFLAGS+= -DTEST_LONG_DOUBLE
# Not sure why this isn't defined for all architectures, since most
diff --git a/lib/libc/tests/gen/posix_spawn_test.c b/lib/libc/tests/gen/posix_spawn_test.c
index e04d103e1a30..5e2c485473d0 100644
--- a/lib/libc/tests/gen/posix_spawn_test.c
+++ b/lib/libc/tests/gen/posix_spawn_test.c
@@ -93,11 +93,50 @@ ATF_TC_BODY(posix_spawn_no_such_command_negative_test, tc)
}
}
+ATF_TC_WITHOUT_HEAD(posix_spawnp_enoexec_fallback);
+ATF_TC_BODY(posix_spawnp_enoexec_fallback, tc)
+{
+ char buf[FILENAME_MAX];
+ char *myargs[2];
+ int error, status;
+ pid_t pid, waitres;
+
+ snprintf(buf, sizeof(buf), "%s/spawnp_enoexec.sh",
+ atf_tc_get_config_var(tc, "srcdir"));
+ myargs[0] = buf;
+ myargs[1] = NULL;
+ error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv);
+ ATF_REQUIRE(error == 0);
+ waitres = waitpid(pid, &status, 0);
+ ATF_REQUIRE(waitres == pid);
+ ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
+}
+
+ATF_TC_WITHOUT_HEAD(posix_spawnp_enoexec_fallback_null_argv0);
+ATF_TC_BODY(posix_spawnp_enoexec_fallback_null_argv0, tc)
+{
+ char buf[FILENAME_MAX];
+ char *myargs[1];
+ int error, status;
+ pid_t pid, waitres;
+
+ snprintf(buf, sizeof(buf), "%s/spawnp_enoexec.sh",
+ atf_tc_get_config_var(tc, "srcdir"));
+ myargs[0] = NULL;
+ error = posix_spawnp(&pid, buf, NULL, NULL, myargs, myenv);
+ ATF_REQUIRE(error == 0);
+ waitres = waitpid(pid, &status, 0);
+ ATF_REQUIRE(waitres == pid);
+ ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, posix_spawn_simple_test);
ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test);
+ ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback);
+ ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback_null_argv0);
return (atf_no_error());
}