Unverified Commit a6205fa5 by Edward Thomson Committed by GitHub

Merge pull request #6636 from libgit2/cmn/ssh-eoo

parents 4939fa74 7a060cc5
...@@ -132,6 +132,22 @@ static int get_ssh_cmdline( ...@@ -132,6 +132,22 @@ static int get_ssh_cmdline(
const char *default_ssh_cmd = "ssh"; const char *default_ssh_cmd = "ssh";
int error; int error;
/*
* Safety check: like git, we forbid paths that look like an
* option as that could lead to injection to ssh that can make
* us do unexpected things
*/
if (git_process__is_cmdline_option(url->username)) {
git_error_set(GIT_ERROR_NET, "cannot ssh: username '%s' is ambiguous with command-line option", url->username);
return -1;
} else if (git_process__is_cmdline_option(url->host)) {
git_error_set(GIT_ERROR_NET, "cannot ssh: host '%s' is ambiguous with command-line option", url->host);
return -1;
} else if (git_process__is_cmdline_option(url->path)) {
git_error_set(GIT_ERROR_NET, "cannot ssh: path '%s' is ambiguous with command-line option", url->path);
return -1;
}
if ((error = git_repository_config_snapshot(&cfg, repo)) < 0) if ((error = git_repository_config_snapshot(&cfg, repo)) < 0)
return error; return error;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "runtime.h" #include "runtime.h"
#include "net.h" #include "net.h"
#include "smart.h" #include "smart.h"
#include "process.h"
#include "streams/socket.h" #include "streams/socket.h"
#include "sysdir.h" #include "sysdir.h"
...@@ -788,6 +789,15 @@ static int _git_ssh_setup_conn( ...@@ -788,6 +789,15 @@ static int _git_ssh_setup_conn(
if (error < 0) if (error < 0)
goto done; goto done;
/* Safety check: like git, we forbid paths that look like an option as
* that could lead to injection on the remote side */
if (git_process__is_cmdline_option(s->url.path)) {
git_error_set(GIT_ERROR_NET, "cannot ssh: path '%s' is ambiguous with command-line option", s->url.path);
error = -1;
goto done;
}
if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 ||
(error = git_stream_connect(s->io)) < 0) (error = git_stream_connect(s->io)) < 0)
goto done; goto done;
......
...@@ -106,6 +106,17 @@ extern int git_process__cmdline( ...@@ -106,6 +106,17 @@ extern int git_process__cmdline(
#endif #endif
/*
* Whether the given string looks like a command line option (starts
* with a dash). This is useful for examining strings that will become
* cmdline arguments to ensure that they are not erroneously treated
* as an option. For example, arguments to `ssh`.
*/
GIT_INLINE(bool) git_process__is_cmdline_option(const char *str)
{
return (str && str[0] == '-');
}
/** /**
* Start the process. * Start the process.
* *
......
#include "clar_libgit2.h"
#include "git2/sys/remote.h"
#include "git2/sys/transport.h"
void test_transport_ssh_exec__reject_injection_username(void)
{
#ifndef GIT_SSH_EXEC
cl_skip();
#else
git_remote *remote;
git_repository *repo;
git_transport *transport;
const char *url = "-oProxyCommand=git@somehost:somepath";
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "./transport-username", 0));
cl_git_pass(git_remote_create(&remote, repo, "test",
cl_fixture("testrepo.git")));
cl_git_pass(git_transport_new(&transport, remote, url));
cl_git_fail_with(-1, transport->connect(transport, url,
GIT_SERVICE_UPLOADPACK_LS, &opts));
transport->free(transport);
git_remote_free(remote);
git_repository_free(repo);
#endif
}
void test_transport_ssh_exec__reject_injection_hostname(void)
{
#ifndef GIT_SSH_EXEC
cl_skip();
#else
git_remote *remote;
git_repository *repo;
git_transport *transport;
const char *url = "-oProxyCommand=somehost:somepath-hostname";
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "./transport-hostname", 0));
cl_git_pass(git_remote_create(&remote, repo, "test",
cl_fixture("testrepo.git")));
cl_git_pass(git_transport_new(&transport, remote, url));
cl_git_fail_with(-1, transport->connect(transport, url,
GIT_SERVICE_UPLOADPACK_LS, &opts));
transport->free(transport);
git_remote_free(remote);
git_repository_free(repo);
#endif
}
void test_transport_ssh_exec__reject_injection_path(void)
{
#ifndef GIT_SSH_EXEC
cl_skip();
#else
git_remote *remote;
git_repository *repo;
git_transport *transport;
const char *url = "git@somehost:-somepath";
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "./transport-path", 0));
cl_git_pass(git_remote_create(&remote, repo, "test",
cl_fixture("testrepo.git")));
cl_git_pass(git_transport_new(&transport, remote, url));
cl_git_fail_with(-1, transport->connect(transport, url,
GIT_SERVICE_UPLOADPACK_LS, &opts));
transport->free(transport);
git_remote_free(remote);
git_repository_free(repo);
#endif
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment