jruby_sandbox 0.1.1-java → 0.1.2-java

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -7,7 +7,7 @@ GIT
7
7
  PATH
8
8
  remote: .
9
9
  specs:
10
- jruby_sandbox (0.1.0-java)
10
+ jruby_sandbox (0.1.1-java)
11
11
  fakefs
12
12
 
13
13
  GEM
data/README.md CHANGED
@@ -56,10 +56,24 @@ Sandbox::Safe exposes an `#activate!` method which will lock down the sandbox, r
56
56
 
57
57
  Sandbox::Safe works by whitelisting methods to keep, and removing the rest. Checkout sandbox.rb for which methods are kept.
58
58
 
59
+ Sandbox::Safe.activate! will also isolate the sandbox environment from the filesystem using FakeFS.
60
+
61
+ >> require 'sandbox'
62
+ => true
63
+ >> s = Sandbox.safe
64
+ => #<Sandbox::Safe:0x3fdb8a73>
65
+ >> s.eval('Dir["/"]')
66
+ => ["/"]
67
+ >> s.eval('Dir["/*"]')
68
+ => ["/Applications", "/bin", "/cores", "/dev", etc.]
69
+ > s.activate!
70
+ >> s.eval('Dir["/*"]')
71
+ => []
72
+ > Dir['/*']
73
+ => ["/Applications", "/bin", "/cores", "/dev", etc.]
74
+
59
75
  ## Known Issues / TODOs
60
76
 
61
- * It would be a good idea to integrate something like FakeFS to stub
62
- out the filesystem in the sandbox.
63
77
  * There is currently no timeout support, so it's possible for a
64
78
  sandbox to loop indefinitely and block the host interpreter.
65
79
 
@@ -1,3 +1,3 @@
1
1
  module Sandbox
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
data/lib/sandbox.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'sandbox/sandbox'
2
2
  require 'sandbox/version'
3
3
  require 'fakefs/safe'
4
+ require 'timeout'
4
5
 
5
6
  module Sandbox
6
7
  PRELUDE = File.expand_path('../sandbox/prelude.rb', __FILE__).freeze # :nodoc:
@@ -22,6 +23,7 @@ module Sandbox
22
23
  keep_singleton_methods(:Kernel, KERNEL_S_METHODS)
23
24
  keep_singleton_methods(:Symbol, SYMBOL_S_METHODS)
24
25
  keep_singleton_methods(:String, STRING_S_METHODS)
26
+ keep_singleton_methods(:IO, IO_S_METHODS)
25
27
 
26
28
  keep_methods(:Kernel, KERNEL_METHODS)
27
29
  keep_methods(:NilClass, NILCLASS_METHODS)
@@ -63,6 +65,24 @@ module Sandbox
63
65
 
64
66
  FakeFS::FileSystem.clear
65
67
  end
68
+
69
+ def eval_with_timeout(code, timeout=10)
70
+ require 'timeout'
71
+
72
+ timeout_code = <<-RUBY
73
+ Timeout.timeout(#{timeout}) do
74
+ #{code}
75
+ end
76
+ RUBY
77
+
78
+ eval timeout_code
79
+ end
80
+
81
+ IO_S_METHODS = %w[
82
+ new
83
+ foreach
84
+ open
85
+ ]
66
86
 
67
87
  KERNEL_S_METHODS = %w[
68
88
  Array
@@ -0,0 +1,123 @@
1
+ require 'rspec'
2
+ require 'sandbox'
3
+
4
+ class OutsideFoo
5
+ def self.bar; 'bar'; end
6
+ end
7
+
8
+ describe "Sandbox exploits" do
9
+ subject { Sandbox.safe }
10
+
11
+ before(:each) do
12
+ subject.activate!
13
+ end
14
+
15
+ it "should not allow running any commands or reading files using IO" do
16
+ expect {
17
+ subject.eval 'f=IO.popen("uname"); f.readlines; f.close'
18
+ }.to raise_error(Sandbox::SandboxException, /NoMethodError/)
19
+
20
+ expect {
21
+ subject.eval 'IO.binread("/etc/passwd")'
22
+ }.to raise_error(Sandbox::SandboxException, /NoMethodError/)
23
+
24
+ expect {
25
+ subject.eval 'IO.read("/etc/passwd")'
26
+ }.to raise_error(Sandbox::SandboxException, /NoMethodError/)
27
+ end
28
+
29
+ it "should not pass through methods added to Kernel" do
30
+ k = subject.eval("Kernel")
31
+ def k.crack
32
+ open("/etc/passwd")
33
+ end
34
+
35
+ Kernel.should respond_to(:crack)
36
+ subject.eval("Kernel.respond_to?(:crack)").should == false
37
+ end
38
+
39
+ it "should not allow calling fork on Kernel, even through eval" do
40
+ subject.eval("eval('Kernel').respond_to?(:fork)").should == false
41
+ end
42
+
43
+ it "should not get access to outside the box objects by using eval and TOPLEVEL_BINDING" do
44
+ expect {
45
+ subject.eval(%{eval('OutsideFoo.bar', TOPLEVEL_BINDING)})
46
+ }.to raise_error(Sandbox::SandboxException, /NameError/)
47
+ end
48
+
49
+ it "should not get access to the outside eval through a ref'd object" do
50
+ subject.ref OutsideFoo
51
+ subject.eval "obj = OutsideFoo.new"
52
+ subject.eval("(obj.methods.grep /^eval/).empty?").should == true
53
+ subject.eval("obj.respond_to?(:eval)").should == false
54
+ end
55
+
56
+ it "should not allow file access, even through a ref hack" do
57
+ unsafe_open = %{File.open('/etc/passwd').read}
58
+
59
+ expect {
60
+ subject.eval(unsafe_open)
61
+ }.to raise_error(Sandbox::SandboxException)
62
+
63
+ subject.ref OutsideFoo
64
+ subject.eval "obj = OutsideFoo.new"
65
+
66
+ unsafe_open_hack = %{obj.eval "#{unsafe_open}"}
67
+
68
+ pending "gotta figure out how to lock down ref'd objects eval" do
69
+ expect {
70
+ subject.eval(unsafe_open_hack)
71
+ }.to raise_error(Sandbox::SandboxException)
72
+ end
73
+ end
74
+
75
+ it "should have safe globals" do
76
+ subject.eval('$0').should == '(sandbox)'
77
+ /(.)(.)(.)/.match("abc")
78
+ subject.eval("$TEST = 'TEST'; $TEST").should == "TEST"
79
+ subject.eval("/(.)(.)(.)/.match('def'); $2").should == "e"
80
+ $2.should == "b"
81
+ subject.eval("$TEST").should == "TEST"
82
+ subject.eval("$2").should == "e"
83
+ end
84
+
85
+ it "should not keep Kernel.fork" do
86
+ expect {
87
+ subject.eval("Kernel.fork")
88
+ }.to raise_error(Sandbox::SandboxException)
89
+
90
+ expect {
91
+ subject.eval("fork")
92
+ }.to raise_error(Sandbox::SandboxException)
93
+ end
94
+
95
+ it "should not allow the sandbox to get back to Kernel through ancestors" do
96
+ subject.eval('$0.class.ancestors[3].respond_to?(:fork)').should == false
97
+ end
98
+
99
+ it "should not pass through block scope" do
100
+ 1.times do |i|
101
+ subject.eval('local_variables').should == []
102
+ end
103
+ end
104
+
105
+ it "should not allow exploits through match data" do
106
+ subject.eval("begin; /(.+)/.match('FreakyFreaky').instance_eval { open('/etc/passwd') }; rescue NameError; :NameError; end").should == :NameError
107
+
108
+ subject.eval("begin;(begin;Regexp.new('(');rescue e;e;end).instance_eval{ open('/etc/passwd') }; rescue NameError; :NameError; end").should == :NameError
109
+ end
110
+
111
+ it "should not be able to access outside box Kernel through exceptions" do
112
+ exception_code = <<-RUBY
113
+ begin
114
+ raise
115
+ rescue => e
116
+ obj = e
117
+ end
118
+ RUBY
119
+ subject.eval(exception_code)
120
+
121
+ subject.eval('obj.class.ancestors[4].respond_to?(:fork)').should == false
122
+ end
123
+ end
data/spec/sandbox_spec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rspec'
2
2
  require 'sandbox'
3
+ require 'timeout'
3
4
 
4
5
  describe Sandbox do
5
6
  after(:each) do
@@ -56,17 +57,6 @@ describe Sandbox do
56
57
  subject.eval(%{FileUtils.cp('/bar.txt', '/baz.txt')})
57
58
  }.to_not raise_error(Sandbox::SandboxException, /NoMethodError/)
58
59
  end
59
-
60
- it "sandboxes global variables" do
61
- subject.eval('$0').should == '(sandbox)'
62
- /(.)(.)(.)/.match('abc')
63
- subject.eval('$TEST = "TEST"; $TEST').should == 'TEST'
64
- subject.eval('/(.)(.)(.)/.match("def"); $2').should == 'e'
65
- $2.should == 'b'
66
- subject.eval('$TEST').should == 'TEST'
67
- subject.eval('$2').should == 'e'
68
- /(.)(.)(.)/.match('ghi')
69
- end
70
60
  end
71
61
 
72
62
  describe ".current" do
@@ -82,6 +72,38 @@ describe Sandbox do
82
72
  end
83
73
  end
84
74
  end
75
+
76
+ describe "#eval_with_timeout" do
77
+ subject { Sandbox.safe }
78
+
79
+ context "before it's been activated" do
80
+ it "should protect against long running code" do
81
+ long_code = <<-RUBY
82
+ sleep(5)
83
+ RUBY
84
+
85
+ expect {
86
+ subject.eval_with_timeout(long_code, 1)
87
+ }.to raise_error(Sandbox::SandboxException, /Timeout/)
88
+ end
89
+ end
90
+
91
+ context "after it's been activated" do
92
+ before(:each) { subject.activate! }
93
+
94
+ it "should protect against long running code" do
95
+ long_code = <<-RUBY
96
+ while true; end
97
+ RUBY
98
+
99
+ expect {
100
+ Timeout.timeout(3) do
101
+ subject.eval_with_timeout(long_code, 1)
102
+ end
103
+ }.to raise_error(Sandbox::SandboxException, /Timeout/)
104
+ end
105
+ end
106
+ end
85
107
 
86
108
  describe "#eval" do
87
109
  subject { Sandbox.new }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jruby_sandbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: java
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-09-20 00:00:00.000000000Z
13
+ date: 2011-09-22 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: fakefs
17
- requirement: &70184226086860 !ruby/object:Gem::Requirement
17
+ requirement: &70213141993840 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70184226086860
25
+ version_requirements: *70213141993840
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rake
28
- requirement: &70184226086440 !ruby/object:Gem::Requirement
28
+ requirement: &70213141992860 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *70184226086440
36
+ version_requirements: *70213141992860
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: rake-compiler
39
- requirement: &70184226086020 !ruby/object:Gem::Requirement
39
+ requirement: &70213141991920 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *70184226086020
47
+ version_requirements: *70213141991920
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: rspec
50
- requirement: &70184226085600 !ruby/object:Gem::Requirement
50
+ requirement: &70213141991120 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: '0'
56
56
  type: :development
57
57
  prerelease: false
58
- version_requirements: *70184226085600
58
+ version_requirements: *70213141991120
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: yard
61
- requirement: &70184226085180 !ruby/object:Gem::Requirement
61
+ requirement: &70213141989820 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: '0'
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *70184226085180
69
+ version_requirements: *70213141989820
70
70
  description: A version of _why's Freaky Freaky Sandbox for JRuby.
71
71
  email:
72
72
  - dray@envylabs.com
@@ -90,6 +90,7 @@ files:
90
90
  - lib/sandbox.rb
91
91
  - lib/sandbox/prelude.rb
92
92
  - lib/sandbox/version.rb
93
+ - spec/exploits_spec.rb
93
94
  - spec/sandbox_spec.rb
94
95
  - spec/support/foo.txt
95
96
  - lib/sandbox/sandbox.jar
@@ -118,5 +119,6 @@ signing_key:
118
119
  specification_version: 3
119
120
  summary: Sandbox support for JRuby
120
121
  test_files:
122
+ - spec/exploits_spec.rb
121
123
  - spec/sandbox_spec.rb
122
124
  - spec/support/foo.txt