lib/safe_yaml/load.rb in safe_yaml-1.0.1 vs lib/safe_yaml/load.rb in safe_yaml-1.0.2
- old
+ new
@@ -2,12 +2,38 @@
# This needs to be defined up front in case any internal classes need to base
# their behavior off of this.
module SafeYAML
YAML_ENGINE = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
+ LIBYAML_VERSION = YAML_ENGINE == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : nil
+
+ def self.check_libyaml_version
+ if YAML_ENGINE == "psych" && (LIBYAML_VERSION.nil? || LIBYAML_VERSION < "0.1.6")
+ Kernel.warn <<-EOWARNING.gsub(/^ +/, ' ')
+
+ \e[33mSafeYAML Warning\e[39m
+ \e[33m----------------\e[39m
+
+ \e[31mYou appear to have an outdated version of libyaml (#{LIBYAML_VERSION}) installed on your system.\e[39m
+
+ Prior to 0.1.6, libyaml is vulnerable to a heap overflow exploit from malicious YAML payloads.
+
+ For more info, see:
+ https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/
+
+ The easiest thing to do right now is probably to update Psych to the latest version and enable
+ the 'bundled-libyaml' option, which will install a vendored libyaml with the vulnerability patched:
+
+ \e[32mgem install psych -- --enable-bundled-libyaml\e[39m
+
+ EOWARNING
+ end
+ end
end
+SafeYAML.check_libyaml_version
+
require "set"
require "safe_yaml/deep"
require "safe_yaml/parse/hexadecimal"
require "safe_yaml/parse/sexagesimal"
require "safe_yaml/parse/date"
@@ -34,11 +60,32 @@
:raise_on_unknown_tag => false
})
OPTIONS = Deep.copy(DEFAULT_OPTIONS)
+ PREDEFINED_TAGS = {}
+
+ if YAML_ENGINE == "syck"
+ YAML.tagged_classes.each do |tag, klass|
+ PREDEFINED_TAGS[klass] = tag
+ end
+
+ else
+ # Special tags appear to be hard-coded in Psych:
+ # https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb
+ # Fortunately, there aren't many that SafeYAML doesn't already support.
+ PREDEFINED_TAGS.merge!({
+ Exception => "!ruby/exception",
+ Range => "!ruby/range",
+ Regexp => "!ruby/regexp",
+ })
+ end
+
+ Deep.freeze(PREDEFINED_TAGS)
+
module_function
+
def restore_defaults!
OPTIONS.clear.merge!(Deep.copy(DEFAULT_OPTIONS))
end
def tag_safety_check!(tag, options)
@@ -59,11 +106,11 @@
klass_name = klass.name
raise "#{klass} cannot be anonymous" if klass_name.nil? || klass_name.empty?
# Whitelist any built-in YAML tags supplied by Syck or Psych.
- predefined_tag = predefined_tags[klass]
+ predefined_tag = PREDEFINED_TAGS[klass]
if predefined_tag
OPTIONS[:whitelisted_tags] << predefined_tag
return
end
@@ -74,33 +121,9 @@
when "psych" then "!ruby/#{tag_class}"
when "syck" then "tag:ruby.yaml.org,2002:#{tag_class}"
else raise "unknown YAML_ENGINE #{YAML_ENGINE}"
end
OPTIONS[:whitelisted_tags] << "#{tag_prefix}:#{klass_name}"
- end
-
- def predefined_tags
- if @predefined_tags.nil?
- @predefined_tags = {}
-
- if YAML_ENGINE == "syck"
- YAML.tagged_classes.each do |tag, klass|
- @predefined_tags[klass] = tag
- end
-
- else
- # Special tags appear to be hard-coded in Psych:
- # https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb
- # Fortunately, there aren't many that SafeYAML doesn't already support.
- @predefined_tags.merge!({
- Exception => "!ruby/exception",
- Range => "!ruby/range",
- Regexp => "!ruby/regexp",
- })
- end
- end
-
- @predefined_tags
end
if YAML_ENGINE == "psych"
def tag_is_explicitly_trusted?(tag)
false