diff -Nru git-1.9.1/debian/changelog git-1.9.1/debian/changelog --- git-1.9.1/debian/changelog 2017-05-12 13:32:41.000000000 +0000 +++ git-1.9.1/debian/changelog 2017-08-10 23:37:04.000000000 +0000 @@ -1,3 +1,13 @@ +git (1:1.9.1-1ubuntu0.6) trusty-security; urgency=medium + + * SECURITY UPDATE: Arbitrary code execution on clients through + malicious ssh URLs. + - debian/diff/0019-CVE-2017-1000117.patch: filter out hostnames + that would interpreted as cli arguments to ssh + - CVE-2017-1000117 + + -- Steve Beattie Thu, 10 Aug 2017 16:36:33 -0700 + git (1:1.9.1-1ubuntu0.5) trusty-security; urgency=medium * SECURITY UPDATE: git shell restriction bypass diff -Nru git-1.9.1/debian/diff/0019-CVE-2017-1000117.patch git-1.9.1/debian/diff/0019-CVE-2017-1000117.patch --- git-1.9.1/debian/diff/0019-CVE-2017-1000117.patch 1970-01-01 00:00:00.000000000 +0000 +++ git-1.9.1/debian/diff/0019-CVE-2017-1000117.patch 2017-08-10 23:35:35.000000000 +0000 @@ -0,0 +1,324 @@ +commit 5e0649dc65fe33e8cf38823350e9d7951f6a6346 +Author: Junio C Hamano +Date: Sun Jul 30 14:45:13 2017 -0700 + + Git 2.7.6 + + Signed-off-by: Junio C Hamano + +commit aeeb2d496859419ac1ba1da1162d6f3610f7f1f3 +Author: Jeff King +Date: Fri Jul 28 15:28:55 2017 -0400 + + connect: reject paths that look like command line options + + If we get a repo path like "-repo.git", we may try to invoke + "git-upload-pack -repo.git". This is going to fail, since + upload-pack will interpret it as a set of bogus options. But + let's reject this before we even run the sub-program, since + we would not want to allow any mischief with repo names that + actually are real command-line options. + + You can still ask for such a path via git-daemon, but there's no + security problem there, because git-daemon enters the repo itself + and then passes "." on the command line. + + Signed-off-by: Jeff King + Reviewed-by: Jonathan Nieder + Signed-off-by: Junio C Hamano + +commit 3be4cf09cd3d0747af3ecdb8dc3962a0969b731e +Author: Jeff King +Date: Fri Jul 28 15:26:50 2017 -0400 + + connect: reject dashed arguments for proxy commands + + If you have a GIT_PROXY_COMMAND configured, we will run it + with the host/port on the command-line. If a URL contains a + mischievous host like "--foo", we don't know how the proxy + command may handle it. It's likely to break, but it may also + do something dangerous and unwanted (technically it could + even do something useful, but that seems unlikely). + + We should err on the side of caution and reject this before + we even run the command. + + The hostname check matches the one we do in a similar + circumstance for ssh. The port check is not present for ssh, + but there it's not necessary because the syntax is "-p + ", and there's no ambiguity on the parsing side. + + It's not clear whether you can actually get a negative port + to the proxy here or not. Doing: + + git fetch git://remote:-1234/repo.git + + keeps the "-1234" as part of the hostname, with the default + port of 9418. But it's a good idea to keep this check close + to the point of running the command to make it clear that + there's no way to circumvent it (and at worst it serves as a + belt-and-suspenders check). + + Signed-off-by: Jeff King + Reviewed-by: Jonathan Nieder + Signed-off-by: Junio C Hamano + +commit 2491f77b90c2e5d47acbe7472c17e7de0af74f63 +Author: Jeff King +Date: Fri Jul 28 15:25:45 2017 -0400 + + connect: factor out "looks like command line option" check + + We reject hostnames that start with a dash because they may + be confused for command-line options. Let's factor out that + notion into a helper function, as we'll use it in more + places. And while it's simple now, it's not clear if some + systems might need more complex logic to handle all cases. + + Signed-off-by: Jeff King + Reviewed-by: Jonathan Nieder + Signed-off-by: Junio C Hamano + +commit 2d90add5ad216807ec1433e5367fae730e74a4cb +Author: Jeff King +Date: Fri Jul 28 15:23:32 2017 -0400 + + t5813: add test for hostname starting with dash + + Per the explanation in the previous patch, this should be + (and is) rejected. + + Signed-off-by: Jeff King + Reviewed-by: Jonathan Nieder + Signed-off-by: Junio C Hamano + +commit 820d7650cc670d3e4195aad3a5343158c316e8fa +Author: Junio C Hamano +Date: Wed Jul 26 10:24:20 2017 -0700 + + connect: reject ssh hostname that begins with a dash + + When commands like "git fetch" talk with ssh://$rest_of_URL/, the + code splits $rest_of_URL into components like host, port, etc., and + then spawns the underlying "ssh" program by formulating argv[] array + that has: + + - the path to ssh command taken from GIT_SSH_COMMAND, etc. + + - dashed options like '-batch' (for Tortoise), '-p ' as + needed. + + - ssh_host, which is supposed to be the hostname parsed out of + $rest_of_URL. + + - then the command to be run on the other side, e.g. git + upload-pack. + + If the ssh_host ends up getting '-', the argv[] that is + used to spawn the command becomes something like: + + { "ssh", "-p", "22", "-", "command", "to", "run", NULL } + + which obviously is bogus, but depending on the actual value of + "", will make "ssh" parse and use it as an option. + + Prevent this by forbidding ssh_host that begins with a "-". + + Noticed-by: Joern Schneeweisz of Recurity Labs + Reported-by: Brian at GitLab + Signed-off-by: Junio C Hamano + Reviewed-by: Jeff King + Signed-off-by: Junio C Hamano + +[Ubuntu note: backported to git 1.9.1 -- sbeattie] +--- + Documentation/RelNotes/2.7.6.txt | 25 +++++++++++++++++++++++++ + cache.h | 8 ++++++++ + connect.c | 6 ++++++ + path.c | 5 +++++ + t/t5532-fetch-proxy.sh | 5 +++++ + t/t5810-proto-disable-local.sh | 23 +++++++++++++++++++++++ + t/t5813-proto-disable-ssh.sh | 23 +++++++++++++++++++++++ + tcp.c | 5 +++++ + 8 files changed, 100 insertions(+) + +Index: b/Documentation/RelNotes/2.7.6.txt +=================================================================== +--- /dev/null ++++ b/Documentation/RelNotes/2.7.6.txt +@@ -0,0 +1,25 @@ ++Git v2.7.6 Release Notes ++======================== ++ ++Fixes since v2.7.5 ++------------------ ++ ++ * A "ssh://..." URL can result in a "ssh" command line with a ++ hostname that begins with a dash "-", which would cause the "ssh" ++ command to instead (mis)treat it as an option. This is now ++ prevented by forbidding such a hostname (which will not be ++ necessary in the real world). ++ ++ * Similarly, when GIT_PROXY_COMMAND is configured, the command is ++ run with host and port that are parsed out from "ssh://..." URL; ++ a poorly written GIT_PROXY_COMMAND could be tricked into treating ++ a string that begins with a dash "-". This is now prevented by ++ forbidding such a hostname and port number (again, which will not ++ be necessary in the real world). ++ ++ * In the same spirit, a repository name that begins with a dash "-" ++ is also forbidden now. ++ ++Credits go to Brian Neel at GitLab, Joern Schneeweisz of Recurity ++Labs and Jeff King at GitHub. ++ +Index: b/cache.h +=================================================================== +--- a/cache.h ++++ b/cache.h +@@ -786,6 +786,14 @@ int daemon_avoid_alias(const char *path) + int offset_1st_component(const char *path); + extern int is_ntfs_dotgit(const char *name); + ++/* ++ * 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 LOOKUP_REPLACE_OBJECT 1 + extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag); +Index: b/tcp.c +=================================================================== +--- a/tcp.c ++++ b/tcp.c +@@ -246,6 +246,11 @@ struct child_process *git_proxy_connect( + + 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; +Index: b/connect.c +=================================================================== +--- a/connect.c ++++ b/connect.c +@@ -430,6 +430,9 @@ struct child_process *git_connect(int fd + } else { + conn = xcalloc(1, sizeof(*conn)); + ++ if (looks_like_command_line_option(path)) ++ die("strange pathname '%s' blocked", path); ++ + strbuf_addstr(&cmd, prog); + strbuf_addch(&cmd, ' '); + sq_quote_buf(&cmd, path); +@@ -445,6 +448,9 @@ struct child_process *git_connect(int fd + get_host_and_port(&ssh_host, &port); + port = get_port_numeric(port); + ++ if (looks_like_command_line_option(ssh_host)) ++ die("strange hostname '%s' blocked", ssh_host); ++ + if (!ssh) ssh = "ssh"; + + *arg++ = ssh; +Index: b/path.c +=================================================================== +--- a/path.c ++++ b/path.c +@@ -863,3 +863,8 @@ int is_ntfs_dotgit(const char *name) + len = -1; + } + } ++ ++int looks_like_command_line_option(const char *str) ++{ ++ return str && str[0] == '-'; ++} +Index: b/t/t5532-fetch-proxy.sh +=================================================================== +--- a/t/t5532-fetch-proxy.sh ++++ b/t/t5532-fetch-proxy.sh +@@ -40,4 +40,9 @@ test_expect_success 'fetch through proxy + 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 +Index: b/t/t5810-proto-disable-local.sh +=================================================================== +--- a/t/t5810-proto-disable-local.sh ++++ b/t/t5810-proto-disable-local.sh +@@ -11,4 +11,27 @@ test_expect_success 'setup repository to + test_proto "file://" file "file://$PWD" + test_proto "path" file . + ++test_expect_success 'setup repo with dash' ' ++ git init --bare repo.git && ++ git push repo.git HEAD && ++ mv repo.git "$PWD/-repo.git" ++' ++ ++# This will fail even without our rejection because upload-pack will ++# complain about the bogus option. So let's make sure that GIT_TRACE ++# doesn't show us even running upload-pack. ++# ++# We must also be sure to use "fetch" and not "clone" here, as the latter ++# actually canonicalizes our input into an absolute path (which is fine ++# to allow). ++test_expect_success 'repo names starting with dash are rejected' ' ++ rm -f trace.out && ++ test_must_fail env GIT_TRACE="$PWD/trace.out" git fetch -- -repo.git && ++ ! grep upload-pack trace.out ++' ++ ++test_expect_success 'full paths still work' ' ++ git fetch "$PWD/-repo.git" ++' ++ + test_done +Index: b/t/t5813-proto-disable-ssh.sh +=================================================================== +--- a/t/t5813-proto-disable-ssh.sh ++++ b/t/t5813-proto-disable-ssh.sh +@@ -17,4 +17,27 @@ test_proto "host:path" ssh "remote:repo. + test_proto "ssh://" ssh "ssh://remote/$PWD/remote/repo.git" + test_proto "git+ssh://" ssh "git+ssh://remote/$PWD/remote/repo.git" + ++# Don't even bother setting up a "-remote" directory, as ssh would generally ++# complain about the bogus option rather than completing our request. Our ++# fake wrapper actually _can_ handle this case, but it's more robust to ++# simply confirm from its output that it did not run at all. ++test_expect_success 'hostnames starting with dash are rejected' ' ++ test_must_fail git clone ssh://-remote/repo.git dash-host 2>stderr && ++ ! grep ^ssh: stderr ++' ++ ++test_expect_success 'setup repo with dash' ' ++ git init --bare remote/-repo.git && ++ git push remote/-repo.git HEAD ++' ++ ++test_expect_success 'repo names starting with dash are rejected' ' ++ test_must_fail git clone remote:-repo.git dash-path 2>stderr && ++ ! grep ^ssh: stderr ++' ++ ++test_expect_success 'full paths still work' ' ++ git clone "remote:$PWD/remote/-repo.git" dash-path ++' ++ + test_done