diff options
author | Jacob Vosmaer <jacob@gitlab.com> | 2019-11-06 12:45:58 +0300 |
---|---|---|
committer | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2019-11-06 12:45:58 +0300 |
commit | dafab928e8e4f43e39bf15f8f50f41a624a2cb11 (patch) | |
tree | f09c3246862b0872e90a66709a96d223d9f37e40 /ruby/lib | |
parent | d509fbe28c14fe55f3e421e7a8abd56ffd981c5a (diff) |
Stricter SSH argument checks
Diffstat (limited to 'ruby/lib')
-rw-r--r-- | ruby/lib/gitlab/git/ssh_auth.rb | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/ruby/lib/gitlab/git/ssh_auth.rb b/ruby/lib/gitlab/git/ssh_auth.rb index 80cb6401c..07cff31bc 100644 --- a/ruby/lib/gitlab/git/ssh_auth.rb +++ b/ruby/lib/gitlab/git/ssh_auth.rb @@ -1,3 +1,5 @@ +require 'shellwords' + module Gitlab module Git # SshAuth writes custom identity and known_hosts files to temporary files @@ -9,6 +11,31 @@ module Gitlab # # Run commands here with the provided environment # end class SshAuth + class Option + def initialize(key, value) + if key.include?('=') || needs_escape?(key) + raise ArgumentError, "invalid SSH config key: #{key.inspect}" + end + + if needs_escape?(value) + raise ArgumentError, "invalid SSH config value: #{value.inspect}" + end + + @key = key + @value = value + end + + def to_s + "-o#{@key}=#{@value}" + end + + private + + def needs_escape?(str) + Shellwords.shellescape(str) != str + end + end + attr_reader :ssh_key, :known_hosts def self.from_gitaly(request) @@ -21,20 +48,20 @@ module Gitlab end def setup - options = {} + options = [] if ssh_key.present? key_file = write_tempfile('gitlab-shell-key-file', 0o400, ssh_key) - options['IdentityFile'] = key_file.path - options['IdentitiesOnly'] = 'yes' + options << Option.new('IdentityFile', key_file.path) + options << Option.new('IdentitiesOnly', 'yes') end if known_hosts.present? known_hosts_file = write_tempfile('gitlab-shell-known-hosts', 0o400, known_hosts) - options['StrictHostKeyChecking'] = 'yes' - options['UserKnownHostsFile'] = known_hosts_file.path + options << Option.new('StrictHostKeyChecking', 'yes') + options << Option.new('UserKnownHostsFile', known_hosts_file.path) end yield custom_environment(options) @@ -57,16 +84,10 @@ module Gitlab # Constructs an environment that will make SSH, as invoked by git, respect # the given options. To achieve this, we use the GIT_SSH_COMMAND envvar. - # - # Options are expanded as `'-oKey="Value"'`, so SSH will correctly - # interpret paths with spaces in them. We trust the rest of this file not - # to embed single or double quotes in the key or value. def custom_environment(options) return {} unless options.present? - args = options.map { |k, v| %('-o#{k}="#{v}"') } - - { 'GIT_SSH_COMMAND' => %(ssh #{args.join(' ')}) } + { 'GIT_SSH_COMMAND' => %(ssh #{options.join(' ')}) } end end end |