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