From c67ed5e85f8f6e021a0630967457e0be4c12bca0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 Feb 2018 13:22:06 +0100 Subject: [PATCH 1/5] git-svn: use '--' to isolate user input in command lines --- fdroidserver/common.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 7f44a4d3..340d296c 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -975,6 +975,7 @@ class vcs_gitsvn(vcs): if not os.path.exists(self.local): # Brand new checkout gitsvn_args = ['svn', 'clone'] + remote = None if ';' in self.remote: remote_split = self.remote.split(';') for i in remote_split[1:]: @@ -984,17 +985,15 @@ class vcs_gitsvn(vcs): gitsvn_args.extend(['-t', i[5:]]) elif i.startswith('branches='): gitsvn_args.extend(['-b', i[9:]]) - gitsvn_args.extend([remote_split[0], self.local]) - p = self.git(gitsvn_args, output=False) - if p.returncode != 0: - self.clone_failed = True - raise VCSException("Git svn clone failed", p.output) + remote = remote_split[0] else: - gitsvn_args.extend([self.remote, self.local]) - p = self.git(gitsvn_args, output=False) - if p.returncode != 0: - self.clone_failed = True - raise VCSException("Git svn clone failed", p.output) + remote = self.remote + + gitsvn_args.extend(['--', remote, self.local]) + p = self.git(gitsvn_args) + if p.returncode != 0: + self.clone_failed = True + raise VCSException(_('git svn clone failed'), p.output) self.checkrepo() else: self.checkrepo() From 574fa15fce6e0bda0272a80b0627a71845bd9583 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 Feb 2018 13:23:44 +0100 Subject: [PATCH 2/5] git: make explicit that git configs are calling cmd line utilities These are not boolean values, but command line utilities which return a guaranteed exit status. --- fdroidserver/common.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 340d296c..86d1a7d1 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -815,7 +815,7 @@ class vcs_git(vcs): # # supported in git >= 2.3 git_config = [ - '-c', 'core.sshCommand=false', + '-c', 'core.sshCommand=/bin/false', '-c', 'url.https://.insteadOf=ssh://', ] for domain in ('bitbucket.org', 'github.com', 'gitlab.com'): @@ -827,7 +827,7 @@ class vcs_git(vcs): git_config.append('url.https://u:p@' + domain + '.insteadOf=https://' + domain) envs.update({ 'GIT_TERMINAL_PROMPT': '0', - 'GIT_SSH': 'false', # for git < 2.3 + 'GIT_SSH': '/bin/false', # for git < 2.3 }) return FDroidPopen(['git', ] + git_config + args, envs=envs, cwd=cwd, output=output) @@ -965,8 +965,8 @@ class vcs_gitsvn(vcs): config = ['-c', 'core.sshCommand=false'] envs.update({ 'GIT_TERMINAL_PROMPT': '0', - 'GIT_SSH': 'false', # for git < 2.3 - 'SVN_SSH': 'false', + 'GIT_SSH': '/bin/false', # for git < 2.3 + 'SVN_SSH': '/bin/false', }) return FDroidPopen(['git', ] + config + args, envs=envs, cwd=cwd, output=output) From dd93ee6c9b2a206fe5e30cdf0a89463683283d0f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 Feb 2018 13:24:32 +0100 Subject: [PATCH 3/5] git: use /bin/true for 'askpass' to prevent all password prompts This uses both the env vars and the command line options to ensure that it works with as many versions of git as possible. Also, git-svn uses the env vars, but not necessarily the command line options. This uses /bin/true to pretend that it succesfully got the password. If password auth is truly required, then it will fail further on down the line. --- fdroidserver/common.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 86d1a7d1..6b34969f 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -815,6 +815,7 @@ class vcs_git(vcs): # # supported in git >= 2.3 git_config = [ + '-c', 'core.askpass=/bin/true', '-c', 'core.sshCommand=/bin/false', '-c', 'url.https://.insteadOf=ssh://', ] @@ -827,6 +828,8 @@ class vcs_git(vcs): git_config.append('url.https://u:p@' + domain + '.insteadOf=https://' + domain) envs.update({ 'GIT_TERMINAL_PROMPT': '0', + 'GIT_ASKPASS': '/bin/true', + 'SSH_ASKPASS': '/bin/true', 'GIT_SSH': '/bin/false', # for git < 2.3 }) return FDroidPopen(['git', ] + git_config + args, @@ -960,15 +963,27 @@ class vcs_gitsvn(vcs): def git(self, args, envs=dict(), cwd=None, output=True): '''Prevent git fetch/clone/submodule from hanging at the username/password prompt + + AskPass is set to /bin/true to let the process try to connect + without a username/password. + + The SSH command is set to /bin/false to block all SSH URLs + (supported in git >= 2.3). This protects against + CVE-2017-1000117. + ''' - # CVE-2017-1000117 block all SSH URLs (supported in git >= 2.3) - config = ['-c', 'core.sshCommand=false'] + git_config = [ + '-c', 'core.askpass=/bin/true', + '-c', 'core.sshCommand=/bin/false', + ] envs.update({ 'GIT_TERMINAL_PROMPT': '0', + 'GIT_ASKPASS': '/bin/true', + 'SSH_ASKPASS': '/bin/true', 'GIT_SSH': '/bin/false', # for git < 2.3 'SVN_SSH': '/bin/false', }) - return FDroidPopen(['git', ] + config + args, + return FDroidPopen(['git', ] + git_config + args, envs=envs, cwd=cwd, output=output) def gotorevisionx(self, rev): From a1075f45cca3919a49192f94da366a423bdb6c4b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 Feb 2018 14:43:39 +0100 Subject: [PATCH 4/5] git-svn: require working HTTPS for all Subversion URLs Subversion does not verify each commit as strongly as git does, so HTTPS is really important. Also, there is the possibility of injecting code into `fdroid checkupdate` calls if plain HTTP is used. --- fdroidserver/common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 6b34969f..938b1c15 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -1004,6 +1004,9 @@ class vcs_gitsvn(vcs): else: remote = self.remote + if not remote.startswith('https://'): + raise VCSException(_('HTTPS must be used with Subversion URLs!')) + gitsvn_args.extend(['--', remote, self.local]) p = self.git(gitsvn_args) if p.returncode != 0: From dc26e7f79f28ba520465b8a2f199c209c7b77350 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 5 Feb 2018 14:44:59 +0100 Subject: [PATCH 5/5] git-svn: check HTTPS connection with Python Requests git-svn will put up the "Reject/Accept" prompt if it encounters a bad HTTPS certificate. I could find no way to stop it from doing that. So instead, this checks the HTTPS connection with an HTTP HEAD request first. --- fdroidserver/common.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 938b1c15..87a9d279 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -1007,6 +1007,11 @@ class vcs_gitsvn(vcs): if not remote.startswith('https://'): raise VCSException(_('HTTPS must be used with Subversion URLs!')) + # git-svn sucks at certificate validation, this throws useful errors: + import requests + r = requests.head(remote) + r.raise_for_status() + gitsvn_args.extend(['--', remote, self.local]) p = self.git(gitsvn_args) if p.returncode != 0: