safe_yaml 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|