From 8a833c720e91c7b4d764e85c30e3be18ee5221fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 4 Apr 2019 15:00:56 +0000 Subject: Allow to use untrusted Regexp via feature flag This brings support for untrusted regexp for 'only:refs:' when enabled via feature flag: alllow_unsafe_ruby_regexp. This is by default disabled, and should not be used in production --- lib/gitlab/untrusted_regexp/ruby_syntax.rb | 39 ++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'lib/gitlab/untrusted_regexp') diff --git a/lib/gitlab/untrusted_regexp/ruby_syntax.rb b/lib/gitlab/untrusted_regexp/ruby_syntax.rb index 91f300f97d0..6adf119aa75 100644 --- a/lib/gitlab/untrusted_regexp/ruby_syntax.rb +++ b/lib/gitlab/untrusted_regexp/ruby_syntax.rb @@ -6,7 +6,7 @@ module Gitlab # and converts that to RE2 representation: # // class RubySyntax - PATTERN = %r{^/(?.+)/(?[ismU]*)$}.freeze + PATTERN = %r{^/(?.*)/(?[ismU]*)$}.freeze # Checks if pattern matches a regexp pattern # but does not enforce it's validity @@ -16,28 +16,47 @@ module Gitlab # The regexp can match the pattern `/.../`, but may not be fabricatable: # it can be invalid or incomplete: `/match ( string/` - def self.valid?(pattern) - !!self.fabricate(pattern) + def self.valid?(pattern, fallback: false) + !!self.fabricate(pattern, fallback: fallback) end - def self.fabricate(pattern) - self.fabricate!(pattern) + def self.fabricate(pattern, fallback: false) + self.fabricate!(pattern, fallback: fallback) rescue RegexpError nil end - def self.fabricate!(pattern) + def self.fabricate!(pattern, fallback: false) raise RegexpError, 'Pattern is not string!' unless pattern.is_a?(String) matches = pattern.match(PATTERN) raise RegexpError, 'Invalid regular expression!' if matches.nil? - expression = matches[:regexp] - flags = matches[:flags] - expression.prepend("(?#{flags})") if flags.present? + begin + create_untrusted_regexp(matches[:regexp], matches[:flags]) + rescue RegexpError + raise unless fallback && + Feature.enabled?(:allow_unsafe_ruby_regexp, default_enabled: false) - UntrustedRegexp.new(expression, multiline: false) + create_ruby_regexp(matches[:regexp], matches[:flags]) + end end + + def self.create_untrusted_regexp(pattern, flags) + pattern.prepend("(?#{flags})") if flags.present? + + UntrustedRegexp.new(pattern, multiline: false) + end + private_class_method :create_untrusted_regexp + + def self.create_ruby_regexp(pattern, flags) + options = 0 + options += Regexp::IGNORECASE if flags&.include?('i') + options += Regexp::MULTILINE if flags&.include?('m') + + Regexp.new(pattern, options) + end + private_class_method :create_ruby_regexp end end end -- cgit v1.2.3