Blame SOURCES/0001-run-command-mark-path-lookup-errors-with-ENOENT.patch

6743a1
From 1e1167f676252c220fbee6038715157c457c7d2f Mon Sep 17 00:00:00 2001
6743a1
From: Jeff King <peff@peff.net>
6743a1
Date: Wed, 24 Oct 2018 03:38:00 -0400
6743a1
Subject: [PATCH] run-command: mark path lookup errors with ENOENT
6743a1
6743a1
Since commit e3a434468f (run-command: use the
6743a1
async-signal-safe execv instead of execvp, 2017-04-19),
6743a1
prepare_cmd() does its own PATH lookup for any commands we
6743a1
run (on non-Windows platforms).
6743a1
6743a1
However, its logic does not match the old execvp call when
6743a1
we fail to find a matching entry in the PATH. Instead of
6743a1
feeding the name directly to execv, execvp would consider
6743a1
that an ENOENT error. By continuing and passing the name
6743a1
directly to execv, we effectively behave as if "." was
6743a1
included at the end of the PATH. This can have confusing and
6743a1
even dangerous results.
6743a1
6743a1
The fix itself is pretty straight-forward. There's a new
6743a1
test in t0061 to cover this explicitly, and I've also added
6743a1
a duplicate of the ENOENT test to ensure that we return the
6743a1
correct errno for this case.
6743a1
6743a1
Signed-off-by: Jeff King <peff@peff.net>
6743a1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
6743a1
---
6743a1
 run-command.c          | 21 +++++++++++++++++----
6743a1
 t/t0061-run-command.sh | 13 ++++++++++++-
6743a1
 2 files changed, 29 insertions(+), 5 deletions(-)
6743a1
6743a1
diff --git a/run-command.c b/run-command.c
6743a1
index 84b883c213..d679cc267c 100644
6743a1
--- a/run-command.c
6743a1
+++ b/run-command.c
6743a1
@@ -380,7 +380,7 @@ static void child_err_spew(struct child_process *cmd, struct child_err *cerr)
6743a1
 	set_error_routine(old_errfn);
6743a1
 }
6743a1
 
6743a1
-static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
6743a1
+static int prepare_cmd(struct argv_array *out, const struct child_process *cmd)
6743a1
 {
6743a1
 	if (!cmd->argv[0])
6743a1
 		BUG("command is empty");
6743a1
@@ -403,16 +403,22 @@ static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
6743a1
 	/*
6743a1
 	 * If there are no '/' characters in the command then perform a path
6743a1
 	 * lookup and use the resolved path as the command to exec.  If there
6743a1
-	 * are no '/' characters or if the command wasn't found in the path,
6743a1
-	 * have exec attempt to invoke the command directly.
6743a1
+	 * are '/' characters, we have exec attempt to invoke the command
6743a1
+	 * directly.
6743a1
 	 */
6743a1
 	if (!strchr(out->argv[1], '/')) {
6743a1
 		char *program = locate_in_PATH(out->argv[1]);
6743a1
 		if (program) {
6743a1
 			free((char *)out->argv[1]);
6743a1
 			out->argv[1] = program;
6743a1
+		} else {
6743a1
+			argv_array_clear(out);
6743a1
+			errno = ENOENT;
6743a1
+			return -1;
6743a1
 		}
6743a1
 	}
6743a1
+
6743a1
+	return 0;
6743a1
 }
6743a1
 
6743a1
 static char **prep_childenv(const char *const *deltaenv)
6743a1
@@ -719,6 +725,12 @@ int start_command(struct child_process *cmd)
6743a1
 	struct child_err cerr;
6743a1
 	struct atfork_state as;
6743a1
 
6743a1
+	if (prepare_cmd(&argv, cmd) < 0) {
6743a1
+		failed_errno = errno;
6743a1
+		cmd->pid = -1;
6743a1
+		goto end_of_spawn;
6743a1
+	}
6743a1
+
6743a1
 	if (pipe(notify_pipe))
6743a1
 		notify_pipe[0] = notify_pipe[1] = -1;
6743a1
 
6743a1
@@ -729,7 +741,6 @@ int start_command(struct child_process *cmd)
6743a1
 		set_cloexec(null_fd);
6743a1
 	}
6743a1
 
6743a1
-	prepare_cmd(&argv, cmd);
6743a1
 	childenv = prep_childenv(cmd->env);
6743a1
 	atfork_prepare(&as);
6743a1
 
6743a1
@@ -857,6 +868,8 @@ int start_command(struct child_process *cmd)
6743a1
 	argv_array_clear(&argv);
6743a1
 	free(childenv);
6743a1
 }
6743a1
+end_of_spawn:
6743a1
+
6743a1
 #else
6743a1
 {
6743a1
 	int fhin = 0, fhout = 1, fherr = 2;
6743a1
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
6743a1
index c887ed5b45..b9cfc03a53 100755
6743a1
--- a/t/t0061-run-command.sh
6743a1
+++ b/t/t0061-run-command.sh
6743a1
@@ -13,10 +13,14 @@ cat >hello-script <<-EOF
6743a1
 EOF
6743a1
 >empty
6743a1
 
6743a1
-test_expect_success 'start_command reports ENOENT' '
6743a1
+test_expect_success 'start_command reports ENOENT (slash)' '
6743a1
 	test-tool run-command start-command-ENOENT ./does-not-exist
6743a1
 '
6743a1
 
6743a1
+test_expect_success 'start_command reports ENOENT (no slash)' '
6743a1
+	test-tool run-command start-command-ENOENT does-not-exist
6743a1
+'
6743a1
+
6743a1
 test_expect_success 'run_command can run a command' '
6743a1
 	cat hello-script >hello.sh &&
6743a1
 	chmod +x hello.sh &&
6743a1
@@ -26,6 +30,13 @@ test_expect_success 'run_command can run a command' '
6743a1
 	test_cmp empty err
6743a1
 '
6743a1
 
6743a1
+test_expect_success 'run_command is restricted to PATH' '
6743a1
+	write_script should-not-run <<-\EOF &&
6743a1
+	echo yikes
6743a1
+	EOF
6743a1
+	test_must_fail test-tool run-command run-command should-not-run
6743a1
+'
6743a1
+
6743a1
 test_expect_success !MINGW 'run_command can run a script without a #! line' '
6743a1
 	cat >hello <<-\EOF &&
6743a1
 	cat hello-script
6743a1
-- 
6743a1
2.14.4
6743a1