safe_yaml 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/bin/safe_yaml +75 -0
- data/lib/safe_yaml/libyaml_checker.rb +36 -0
- data/lib/safe_yaml/load.rb +2 -27
- data/lib/safe_yaml/version.rb +1 -1
- data/safe_yaml.gemspec +1 -0
- data/spec/libyaml_checker_spec.rb +69 -0
- data/spec/safe_yaml_spec.rb +0 -49
- data/spec/spec_helper.rb +8 -0
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fac2ccd0e0ff144a5b72c1597d16206e9c401753
|
4
|
+
data.tar.gz: c13a8b54286042faf6c3c2caa9fd2ec6d436fe1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5bedc29148ac5d69c163793ef490ad22261c63ca7b390e80f4a405d62a7ccef5d91520344b6901ca785db584bbf197b0ec4a2c55170fa6b6adce6b077151f41
|
7
|
+
data.tar.gz: 77a93e398b12f8661b8fc9ab672b4d5278e5c4e2e6a7c615ee162934ad5b0c23867a94e3d2425f543563e5e04890fc76f96e7e25c99ccc8c94740c1e948212ae
|
data/README.md
CHANGED
@@ -172,6 +172,7 @@ Also be aware that some Ruby libraries, particularly those requiring inter-proce
|
|
172
172
|
1. set the `:deserialize_symbols` option to `true`,
|
173
173
|
2. whitelist some of the types in your serialized data via `SafeYAML.whitelist!` or the `:whitelisted_tags` option, or
|
174
174
|
3. both
|
175
|
+
- [**delayed_job**](https://github.com/collectiveidea/delayed_job): Uses YAML to serialize the objects on which delayed methods are invoked (with `delay`). The safest solution in this case is to use `SafeYAML.whitelist!` to whitelist the types you need to serialize.
|
175
176
|
- [**Guard**](https://github.com/guard/guard): Uses YAML as a serialization format for notifications. The data serialized uses symbolic keys, so setting `SafeYAML::OPTIONS[:deserialize_symbols] = true` is necessary to allow Guard to work.
|
176
177
|
- [**sidekiq**](https://github.com/mperham/sidekiq): Uses a YAML configiuration file with symbolic keys, so setting `SafeYAML::OPTIONS[:deserialize_symbols] = true` should allow it to work.
|
177
178
|
|
data/bin/safe_yaml
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'safe_yaml/load'
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
option_parser = OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: safe_yaml [options]"
|
11
|
+
|
12
|
+
opts.on("-f", "--file=<path>", "Parse the given YAML file, dump the result to STDOUT") do |file|
|
13
|
+
options[:file] = file
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on("--libyaml-check", "Check for libyaml vulnerability CVE-2014-2525 on your system") do
|
17
|
+
options[:libyaml_check] = true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
option_parser.parse!
|
22
|
+
|
23
|
+
def report_libyaml_ok
|
24
|
+
puts "\e[32mGood news! You definitely have either a patched or up-to-date libyaml version :)\e[39m"
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_for_overflow_bug
|
28
|
+
YAML.load("--- !#{'%20' * 100}")
|
29
|
+
report_libyaml_ok
|
30
|
+
end
|
31
|
+
|
32
|
+
def perform_libyaml_check(force=false)
|
33
|
+
unless SafeYAML::LibyamlChecker.libyaml_version_ok?
|
34
|
+
warn <<-EOM.gsub(/^ +/, ' ')
|
35
|
+
|
36
|
+
\e[33mSafeYAML Warning\e[39m
|
37
|
+
\e[33m----------------\e[39m
|
38
|
+
|
39
|
+
\e[31mYou may have an outdated version of libyaml (#{SafeYAML::LibyamlChecker::LIBYAML_VERSION}) installed on your system.\e[39m
|
40
|
+
|
41
|
+
Prior to 0.1.6, libyaml is vulnerable to a heap overflow exploit from malicious YAML payloads.
|
42
|
+
|
43
|
+
For more info, see:
|
44
|
+
https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/
|
45
|
+
EOM
|
46
|
+
end
|
47
|
+
|
48
|
+
puts <<-EOM.gsub(/^ +/, ' ')
|
49
|
+
|
50
|
+
Hit Enter to check if your version of libyaml is vulnerable. This will run a test \e[31mwhich may crash\e[39m
|
51
|
+
\e[31mthe current process\e[39m. If it does, your system is vulnerable and you should do something about it.
|
52
|
+
|
53
|
+
Type "nm" and hit Enter if you don't want to run the check.
|
54
|
+
|
55
|
+
See the project wiki for more info:
|
56
|
+
|
57
|
+
https://github.com/dtao/safe_yaml/wiki/The-libyaml-vulnerability
|
58
|
+
EOM
|
59
|
+
|
60
|
+
if STDIN.readline.chomp("\n") != 'nm'
|
61
|
+
check_for_overflow_bug
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if options[:libyaml_check]
|
66
|
+
perform_libyaml_check(options[:force_libyaml_check])
|
67
|
+
|
68
|
+
elsif options[:file]
|
69
|
+
yaml = File.read(options[:file])
|
70
|
+
result = SafeYAML.load(yaml)
|
71
|
+
puts result.inspect
|
72
|
+
|
73
|
+
else
|
74
|
+
puts option_parser.help
|
75
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module SafeYAML
|
4
|
+
class LibyamlChecker
|
5
|
+
LIBYAML_VERSION = Psych::LIBYAML_VERSION rescue nil
|
6
|
+
|
7
|
+
# Do proper version comparison (e.g. so 0.1.10 is >= 0.1.6)
|
8
|
+
SAFE_LIBYAML_VERSION = Gem::Version.new("0.1.6")
|
9
|
+
|
10
|
+
KNOWN_PATCHED_LIBYAML_VERSIONS = Set.new([
|
11
|
+
# http://people.canonical.com/~ubuntu-security/cve/2014/CVE-2014-2525.html
|
12
|
+
"0.1.4-2ubuntu0.12.04.3",
|
13
|
+
"0.1.4-2ubuntu0.12.10.3",
|
14
|
+
"0.1.4-2ubuntu0.13.10.3",
|
15
|
+
"0.1.4-3ubuntu3",
|
16
|
+
|
17
|
+
# https://security-tracker.debian.org/tracker/CVE-2014-2525
|
18
|
+
"0.1.3-1+deb6u4",
|
19
|
+
"0.1.4-2+deb7u4",
|
20
|
+
"0.1.4-3.2"
|
21
|
+
]).freeze
|
22
|
+
|
23
|
+
def self.libyaml_version_ok?
|
24
|
+
return true if YAML_ENGINE != "psych" || defined?(JRUBY_VERSION)
|
25
|
+
return true if Gem::Version.new(LIBYAML_VERSION || "0") >= SAFE_LIBYAML_VERSION
|
26
|
+
return libyaml_patched?
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.libyaml_patched?
|
30
|
+
return false if (`which dpkg` rescue '').empty?
|
31
|
+
libyaml_version = `dpkg -s libyaml-0-2`.match(/^Version: (.*)$/)
|
32
|
+
return false if libyaml_version.nil?
|
33
|
+
KNOWN_PATCHED_LIBYAML_VERSIONS.include?(libyaml_version[1])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/safe_yaml/load.rb
CHANGED
@@ -1,38 +1,13 @@
|
|
1
|
+
require "set"
|
1
2
|
require "yaml"
|
2
3
|
|
3
4
|
# This needs to be defined up front in case any internal classes need to base
|
4
5
|
# their behavior off of this.
|
5
6
|
module SafeYAML
|
6
7
|
YAML_ENGINE = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
|
7
|
-
LIBYAML_VERSION = YAML_ENGINE == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : nil
|
8
|
-
|
9
|
-
def self.check_libyaml_version
|
10
|
-
if YAML_ENGINE == "psych" && (LIBYAML_VERSION.nil? || LIBYAML_VERSION < "0.1.6")
|
11
|
-
Kernel.warn <<-EOWARNING.gsub(/^ +/, ' ')
|
12
|
-
|
13
|
-
\e[33mSafeYAML Warning\e[39m
|
14
|
-
\e[33m----------------\e[39m
|
15
|
-
|
16
|
-
\e[31mYou appear to have an outdated version of libyaml (#{LIBYAML_VERSION}) installed on your system.\e[39m
|
17
|
-
|
18
|
-
Prior to 0.1.6, libyaml is vulnerable to a heap overflow exploit from malicious YAML payloads.
|
19
|
-
|
20
|
-
For more info, see:
|
21
|
-
https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/
|
22
|
-
|
23
|
-
The easiest thing to do right now is probably to update Psych to the latest version and enable
|
24
|
-
the 'bundled-libyaml' option, which will install a vendored libyaml with the vulnerability patched:
|
25
|
-
|
26
|
-
\e[32mgem install psych -- --enable-bundled-libyaml\e[39m
|
27
|
-
|
28
|
-
EOWARNING
|
29
|
-
end
|
30
|
-
end
|
31
8
|
end
|
32
9
|
|
33
|
-
|
34
|
-
|
35
|
-
require "set"
|
10
|
+
require "safe_yaml/libyaml_checker"
|
36
11
|
require "safe_yaml/deep"
|
37
12
|
require "safe_yaml/parse/hexadecimal"
|
38
13
|
require "safe_yaml/parse/sexagesimal"
|
data/lib/safe_yaml/version.rb
CHANGED
data/safe_yaml.gemspec
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SafeYAML::LibyamlChecker do
|
4
|
+
describe "check_libyaml_version" do
|
5
|
+
REAL_YAML_ENGINE = SafeYAML::YAML_ENGINE
|
6
|
+
REAL_LIBYAML_VERSION = SafeYAML::LibyamlChecker::LIBYAML_VERSION
|
7
|
+
|
8
|
+
let(:libyaml_patched) { false }
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
SafeYAML::LibyamlChecker.stub(:libyaml_patched?).and_return(libyaml_patched)
|
12
|
+
end
|
13
|
+
|
14
|
+
after :each do
|
15
|
+
silence_warnings do
|
16
|
+
SafeYAML::YAML_ENGINE = REAL_YAML_ENGINE
|
17
|
+
SafeYAML::LibyamlChecker::LIBYAML_VERSION = REAL_LIBYAML_VERSION
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_libyaml_version_ok(expected_result, yaml_engine, libyaml_version=nil)
|
22
|
+
silence_warnings do
|
23
|
+
SafeYAML.const_set("YAML_ENGINE", yaml_engine)
|
24
|
+
SafeYAML::LibyamlChecker.const_set("LIBYAML_VERSION", libyaml_version)
|
25
|
+
SafeYAML::LibyamlChecker.libyaml_version_ok?.should == expected_result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless defined?(JRUBY_VERSION)
|
30
|
+
it "issues no warnings when 'Syck' is the YAML engine" do
|
31
|
+
test_libyaml_version_ok(true, "syck")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "issues a warning if Psych::LIBYAML_VERSION is not defined" do
|
35
|
+
test_libyaml_version_ok(false, "psych")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "issues a warning if Psych::LIBYAML_VERSION is < 0.1.6" do
|
39
|
+
test_libyaml_version_ok(false, "psych", "0.1.5")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "issues no warning if Psych::LIBYAML_VERSION is == 0.1.6" do
|
43
|
+
test_libyaml_version_ok(true, "psych", "0.1.6")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "issues no warning if Psych::LIBYAML_VERSION is > 0.1.6" do
|
47
|
+
test_libyaml_version_ok(true, "psych", "1.0.0")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does a proper version comparison (not just a string comparison)" do
|
51
|
+
test_libyaml_version_ok(true, "psych", "0.1.10")
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when the system has a known patched libyaml version" do
|
55
|
+
let(:libyaml_patched) { true }
|
56
|
+
|
57
|
+
it "issues no warning, even when Psych::LIBYAML_VERSION < 0.1.6" do
|
58
|
+
test_libyaml_version_ok(true, "psych", "0.1.4")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if defined?(JRUBY_VERSION)
|
64
|
+
it "issues no warning, as JRuby doesn't use libyaml" do
|
65
|
+
test_libyaml_version_ok(true, "psych", "0.1.4")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/safe_yaml_spec.rb
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe YAML do
|
4
|
-
# Essentially stolen from:
|
5
|
-
# https://github.com/rails/rails/blob/3-2-stable/activesupport/lib/active_support/core_ext/kernel/reporting.rb#L10-25
|
6
|
-
def silence_warnings
|
7
|
-
$VERBOSE = nil; yield
|
8
|
-
ensure
|
9
|
-
$VERBOSE = true
|
10
|
-
end
|
11
|
-
|
12
4
|
def safe_load_round_trip(object, options={})
|
13
5
|
yaml = object.to_yaml
|
14
6
|
if SafeYAML::YAML_ENGINE == "psych"
|
@@ -32,47 +24,6 @@ describe YAML do
|
|
32
24
|
SafeYAML.restore_defaults!
|
33
25
|
end
|
34
26
|
|
35
|
-
describe "check_libyaml_version" do
|
36
|
-
REAL_YAML_ENGINE = SafeYAML::YAML_ENGINE
|
37
|
-
REAL_LIBYAML_VERSION = SafeYAML::LIBYAML_VERSION
|
38
|
-
|
39
|
-
after :each do
|
40
|
-
silence_warnings do
|
41
|
-
SafeYAML::YAML_ENGINE = REAL_YAML_ENGINE
|
42
|
-
SafeYAML::LIBYAML_VERSION = REAL_LIBYAML_VERSION
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_check_libyaml_version(warning_expected, yaml_engine, libyaml_version=nil)
|
47
|
-
silence_warnings do
|
48
|
-
SafeYAML.const_set("YAML_ENGINE", yaml_engine)
|
49
|
-
SafeYAML.const_set("LIBYAML_VERSION", libyaml_version)
|
50
|
-
Kernel.send(warning_expected ? :should_receive : :should_not_receive, :warn)
|
51
|
-
SafeYAML.check_libyaml_version
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it "issues no warnings when 'Syck' is the YAML engine" do
|
56
|
-
test_check_libyaml_version(false, "syck")
|
57
|
-
end
|
58
|
-
|
59
|
-
it "issues a warning if Psych::LIBYAML_VERSION is not defined" do
|
60
|
-
test_check_libyaml_version(true, "psych")
|
61
|
-
end
|
62
|
-
|
63
|
-
it "issues a warning if Psych::LIBYAML_VERSION is < 0.1.6" do
|
64
|
-
test_check_libyaml_version(true, "psych", "0.1.5")
|
65
|
-
end
|
66
|
-
|
67
|
-
it "issues no warning if Psych::LIBYAML_VERSION is == 0.1.6" do
|
68
|
-
test_check_libyaml_version(false, "psych", "0.1.6")
|
69
|
-
end
|
70
|
-
|
71
|
-
it "issues no warning if Psych::LIBYAML_VERSION is > 0.1.6" do
|
72
|
-
test_check_libyaml_version(false, "psych", "1.0.0")
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
27
|
describe "unsafe_load" do
|
77
28
|
if SafeYAML::YAML_ENGINE == "psych" && RUBY_VERSION >= "1.9.3"
|
78
29
|
it "allows exploits through objects defined in YAML w/ !ruby/hash via custom :[]= methods" do
|
data/spec/spec_helper.rb
CHANGED
@@ -31,4 +31,12 @@ require "ostruct"
|
|
31
31
|
require "hashie"
|
32
32
|
require "heredoc_unindent"
|
33
33
|
|
34
|
+
# Stolen from Rails:
|
35
|
+
# https://github.com/rails/rails/blob/3-2-stable/activesupport/lib/active_support/core_ext/kernel/reporting.rb#L10-25
|
36
|
+
def silence_warnings
|
37
|
+
$VERBOSE = nil; yield
|
38
|
+
ensure
|
39
|
+
$VERBOSE = true
|
40
|
+
end
|
41
|
+
|
34
42
|
require File.join(HERE, "resolver_specs")
|
metadata
CHANGED
@@ -1,31 +1,34 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safe_yaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Tao
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Parse YAML safely
|
14
14
|
email: daniel.tao@gmail.com
|
15
|
-
executables:
|
15
|
+
executables:
|
16
|
+
- safe_yaml
|
16
17
|
extensions: []
|
17
18
|
extra_rdoc_files: []
|
18
19
|
files:
|
19
|
-
-
|
20
|
-
-
|
20
|
+
- .gitignore
|
21
|
+
- .travis.yml
|
21
22
|
- CHANGES.md
|
22
23
|
- Gemfile
|
23
24
|
- LICENSE.txt
|
24
25
|
- README.md
|
25
26
|
- Rakefile
|
27
|
+
- bin/safe_yaml
|
26
28
|
- bundle_install_all_ruby_versions.sh
|
27
29
|
- lib/safe_yaml.rb
|
28
30
|
- lib/safe_yaml/deep.rb
|
31
|
+
- lib/safe_yaml/libyaml_checker.rb
|
29
32
|
- lib/safe_yaml/load.rb
|
30
33
|
- lib/safe_yaml/parse/date.rb
|
31
34
|
- lib/safe_yaml/parse/hexadecimal.rb
|
@@ -52,6 +55,7 @@ files:
|
|
52
55
|
- spec/exploit.1.9.3.yaml
|
53
56
|
- spec/issue48.txt
|
54
57
|
- spec/issue49.yml
|
58
|
+
- spec/libyaml_checker_spec.rb
|
55
59
|
- spec/psych_resolver_spec.rb
|
56
60
|
- spec/resolver_specs.rb
|
57
61
|
- spec/safe_yaml_spec.rb
|
@@ -74,17 +78,17 @@ require_paths:
|
|
74
78
|
- lib
|
75
79
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
80
|
requirements:
|
77
|
-
- -
|
81
|
+
- - '>='
|
78
82
|
- !ruby/object:Gem::Version
|
79
83
|
version: 1.8.7
|
80
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
85
|
requirements:
|
82
|
-
- -
|
86
|
+
- - '>='
|
83
87
|
- !ruby/object:Gem::Version
|
84
88
|
version: '0'
|
85
89
|
requirements: []
|
86
90
|
rubyforge_project:
|
87
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.2.2
|
88
92
|
signing_key:
|
89
93
|
specification_version: 4
|
90
94
|
summary: SameYAML provides an alternative implementation of YAML.load suitable for
|
@@ -94,6 +98,7 @@ test_files:
|
|
94
98
|
- spec/exploit.1.9.3.yaml
|
95
99
|
- spec/issue48.txt
|
96
100
|
- spec/issue49.yml
|
101
|
+
- spec/libyaml_checker_spec.rb
|
97
102
|
- spec/psych_resolver_spec.rb
|
98
103
|
- spec/resolver_specs.rb
|
99
104
|
- spec/safe_yaml_spec.rb
|