diff --git a/cache.h b/cache.h index 94ca1ac..2ab9ffd 100644 --- a/cache.h +++ b/cache.h @@ -744,6 +744,14 @@ char *strip_path_suffix(const char *path, const char *suffix); int daemon_avoid_alias(const char *path); int offset_1st_component(const char *path); +/* + * Returns true iff "str" could be confused as a command-line option when + * passed to a sub-program like "ssh". Note that this has nothing to do with + * shell-quoting, which should be handled separately; we're assuming here that + * the string makes it verbatim to the sub-program. + */ +int looks_like_command_line_option(const char *str); + /* object replacement */ #define READ_SHA1_FILE_REPLACE 1 extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag); diff --git a/connect.c b/connect.c index 6d4ea13..970f565 100644 --- a/connect.c +++ b/connect.c @@ -450,6 +450,11 @@ static struct child_process *git_proxy_connect(int fd[2], char *host) get_host_and_port(&host, &port); + if (looks_like_command_line_option(host)) + die("strange hostname '%s' blocked", host); + if (looks_like_command_line_option(port)) + die("strange port '%s' blocked", port); + argv = xmalloc(sizeof(*argv) * 4); argv[0] = git_proxy_command; argv[1] = host; @@ -613,6 +618,10 @@ struct child_process *git_connect(int fd[2], const char *url_orig, conn = xcalloc(1, sizeof(*conn)); + if (looks_like_command_line_option(path)) + die("strange pathname '%s' blocked", path); + + strbuf_init(&cmd, MAX_CMD_LEN); strbuf_addstr(&cmd, prog); strbuf_addch(&cmd, ' '); @@ -626,6 +635,10 @@ struct child_process *git_connect(int fd[2], const char *url_orig, const char *ssh = getenv("GIT_SSH"); int putty = ssh && strcasestr(ssh, "plink"); transport_check_allowed("ssh"); + if (looks_like_command_line_option(host)) + die("strange hostname '%s' blocked", host); + + if (!ssh) ssh = "ssh"; *arg++ = ssh; diff --git a/path.c b/path.c index 04ff148..713d79b 100644 --- a/path.c +++ b/path.c @@ -701,3 +701,9 @@ int offset_1st_component(const char *path) return 2 + is_dir_sep(path[2]); return is_dir_sep(path[0]); } + +int looks_like_command_line_option(const char *str) +{ + return str && str[0] == '-'; +} + diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh index 5531bd1..d3b2651 100755 --- a/t/t5532-fetch-proxy.sh +++ b/t/t5532-fetch-proxy.sh @@ -40,4 +40,9 @@ test_expect_success 'fetch through proxy works' ' test_cmp expect actual ' +test_expect_success 'funny hostnames are rejected before running proxy' ' + test_must_fail git fetch git://-remote/repo.git 2>stderr && + ! grep "proxying for" stderr +' + test_done