xplenty-jruby_sandbox 0.2.4-java
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 +7 -0
- data/.gitignore +9 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.md +91 -0
- data/Rakefile +24 -0
- data/ext/java/sandbox/BoxedClass.java +35 -0
- data/ext/java/sandbox/SandboxFull.java +317 -0
- data/ext/java/sandbox/SandboxModule.java +39 -0
- data/ext/java/sandbox/SandboxProfile.java +22 -0
- data/ext/java/sandbox/SandboxService.java +17 -0
- data/jruby_sandbox.gemspec +28 -0
- data/lib/sandbox/prelude.rb +19 -0
- data/lib/sandbox/safe.rb +417 -0
- data/lib/sandbox/sandbox.jar +0 -0
- data/lib/sandbox/version.rb +3 -0
- data/lib/sandbox.rb +17 -0
- data/spec/exploits_spec.rb +196 -0
- data/spec/sandbox_spec.rb +270 -0
- data/spec/support/foo.txt +1 -0
- metadata +139 -0
@@ -0,0 +1,270 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "sandbox"
|
3
|
+
require "timeout"
|
4
|
+
|
5
|
+
describe Sandbox do
|
6
|
+
after(:each) do
|
7
|
+
Object.class_eval { remove_const(:Foo) } if defined?(Foo)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".new" do
|
11
|
+
subject { Sandbox.new }
|
12
|
+
|
13
|
+
it { should_not be_nil }
|
14
|
+
it { should be_an_instance_of(Sandbox::Full) }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".safe" do
|
18
|
+
subject { Sandbox.safe }
|
19
|
+
|
20
|
+
it { should be_an_instance_of(Sandbox::Safe) }
|
21
|
+
|
22
|
+
it "should not lock down until calling activate!" do
|
23
|
+
subject.eval(%|`echo hello`|).should == "hello\n"
|
24
|
+
|
25
|
+
subject.activate!
|
26
|
+
|
27
|
+
expect {
|
28
|
+
subject.eval(%|`echo hello`|)
|
29
|
+
}.to raise_error(Sandbox::SandboxException)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should activate FakeFS inside the sandbox (and not allow it to be deactivated)" do
|
33
|
+
subject.eval(%|File|).should == ::File
|
34
|
+
|
35
|
+
subject.activate!
|
36
|
+
|
37
|
+
foo = File.join(File.dirname(__FILE__), "support", "foo.txt")
|
38
|
+
|
39
|
+
expect {
|
40
|
+
subject.eval(%{File.read("#{foo}")})
|
41
|
+
}.to raise_error(Sandbox::SandboxException, /Errno::ENOENT: No such file or directory/)
|
42
|
+
|
43
|
+
subject.eval(%|File|).should == FakeFS::File
|
44
|
+
subject.eval(%|Dir|).should == FakeFS::Dir
|
45
|
+
subject.eval(%|FileUtils|).should == FakeFS::FileUtils
|
46
|
+
subject.eval(%|FileTest|).should == FakeFS::FileTest
|
47
|
+
|
48
|
+
subject.eval(%{FakeFS.deactivate!})
|
49
|
+
|
50
|
+
expect {
|
51
|
+
subject.eval(%{File.read("#{foo}")})
|
52
|
+
}.to raise_error(Sandbox::SandboxException, /Errno::ENOENT: No such file or directory/)
|
53
|
+
|
54
|
+
subject.eval(%{File.open("/bar.txt", "w") {|file| file << "bar" }})
|
55
|
+
|
56
|
+
expect {
|
57
|
+
subject.eval(%{FileUtils.cp("/bar.txt", "/baz.txt")})
|
58
|
+
}.to_not raise_error(Sandbox::SandboxException, /NoMethodError/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe ".current" do
|
63
|
+
it "should not return a current sandbox outside a sandbox" do
|
64
|
+
Sandbox.current.should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
# it "should return the current sandbox inside a sandbox" do
|
68
|
+
# pending do
|
69
|
+
# sandbox = Sandbox.new
|
70
|
+
# sandbox.ref(Sandbox)
|
71
|
+
# sandbox.eval(%|Sandbox.current|).should == sandbox
|
72
|
+
# end
|
73
|
+
# end
|
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(long_code, timeout: 1)
|
87
|
+
}.to raise_error(Sandbox::TimeoutError)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not raise a timeout error if the code runs in under the passed in time" do
|
91
|
+
short_code = <<-RUBY
|
92
|
+
1+1
|
93
|
+
RUBY
|
94
|
+
|
95
|
+
expect {
|
96
|
+
subject.eval(short_code, timeout: 1)
|
97
|
+
}.to_not raise_error(Sandbox::TimeoutError)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "after it's been activated" do
|
102
|
+
before(:each) { subject.activate! }
|
103
|
+
|
104
|
+
it "should protect against long running code" do
|
105
|
+
long_code = <<-RUBY
|
106
|
+
while true; end
|
107
|
+
RUBY
|
108
|
+
|
109
|
+
expect {
|
110
|
+
subject.eval(long_code, timeout: 1)
|
111
|
+
}.to raise_error(Sandbox::TimeoutError)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should persist state between evaluations" do
|
115
|
+
subject.eval(%|o = Object.new|, timeout: 1)
|
116
|
+
|
117
|
+
expect {
|
118
|
+
subject.eval(%|o|, timeout: 1)
|
119
|
+
}.to_not raise_error(Sandbox::SandboxException)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "#eval" do
|
125
|
+
subject { Sandbox.new }
|
126
|
+
|
127
|
+
it "should allow a range of common operations" do
|
128
|
+
operations = <<-OPS
|
129
|
+
1 + 1
|
130
|
+
"foo".chomp
|
131
|
+
"foo"
|
132
|
+
OPS
|
133
|
+
subject.eval(operations).should == "foo"
|
134
|
+
end
|
135
|
+
|
136
|
+
# it "should have an empty ENV" do
|
137
|
+
# pending do
|
138
|
+
# subject.eval(%{ENV.to_a}).should be_empty
|
139
|
+
# end
|
140
|
+
# end
|
141
|
+
|
142
|
+
it "should persist state between evaluations" do
|
143
|
+
subject.eval(%|o = Object.new|)
|
144
|
+
subject.eval(%|o|).should_not be_nil
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should be able to define a new class in the sandbox" do
|
148
|
+
result = subject.eval(%|Foo = Struct.new(:foo); struct = Foo.new("baz"); struct.foo|)
|
149
|
+
result.should == "baz"
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should be able to use a class across invocations" do
|
153
|
+
# Return nil, because the environment doesn't know "Foo"
|
154
|
+
subject.eval(%|Foo = Struct.new(:foo); nil|)
|
155
|
+
subject.eval(%|struct = Foo.new("baz"); nil|)
|
156
|
+
subject.eval(%|struct.foo|).should == "baz"
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "communication between sandbox and environment" do
|
160
|
+
it "should be possible to pass data from the box to the environment" do
|
161
|
+
Foo = Struct.new(:foo)
|
162
|
+
subject.ref(Foo)
|
163
|
+
struct = subject.eval(%|struct = Foo.new|)
|
164
|
+
subject.eval(%|struct.foo = "baz"|)
|
165
|
+
struct.foo.should == "baz"
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should be possible to pass data from the environment to the box" do
|
169
|
+
Foo = Struct.new(:foo)
|
170
|
+
subject.ref(Foo)
|
171
|
+
struct = subject.eval(%|struct = Foo.new|)
|
172
|
+
struct.foo = "baz"
|
173
|
+
subject.eval(%|struct.foo|).should == "baz"
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should be able to pass large object data from the box to the environment" do
|
177
|
+
expect {
|
178
|
+
subject.eval %{
|
179
|
+
(0..1000).to_a.inject({}) {|h,i| h[i] = "HELLO WORLD"; h }
|
180
|
+
}
|
181
|
+
}.to_not raise_error(Sandbox::SandboxException)
|
182
|
+
|
183
|
+
expect {
|
184
|
+
subject.eval %{"RUBY"*100}
|
185
|
+
}.to_not raise_error(Sandbox::SandboxException)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#import" do
|
191
|
+
subject { Sandbox.new }
|
192
|
+
|
193
|
+
it "should be able to call a referenced namespaced module method" do
|
194
|
+
Foo = Class.new
|
195
|
+
Foo::Bar = Module.new do
|
196
|
+
def baz
|
197
|
+
"baz"
|
198
|
+
end
|
199
|
+
module_function :baz
|
200
|
+
end
|
201
|
+
|
202
|
+
subject.import(Foo::Bar)
|
203
|
+
subject.eval(%|Foo::Bar.baz|).should == "baz"
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should be able to include a module from the environment" do
|
207
|
+
Foo = Module.new do
|
208
|
+
def baz
|
209
|
+
"baz"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
subject.import(Foo)
|
214
|
+
subject.eval(%|class Bar; include Foo; end; nil|)
|
215
|
+
subject.eval(%|Bar.new.baz|).should == "baz"
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should be able to copy instance methods from a module that uses module_function" do
|
219
|
+
Foo = Module.new do
|
220
|
+
def baz; "baz"; end
|
221
|
+
|
222
|
+
module_function :baz
|
223
|
+
end
|
224
|
+
|
225
|
+
subject.import Foo
|
226
|
+
subject.eval(%|Foo.baz|).should == "baz"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "#ref" do
|
231
|
+
subject { Sandbox.new }
|
232
|
+
|
233
|
+
it "should be possible to reference a class defined outside the box" do
|
234
|
+
Foo = Class.new
|
235
|
+
subject.ref(Foo)
|
236
|
+
subject.eval(%|Foo.new|).should be_an_instance_of(Foo)
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should be possible to change the class after the ref" do
|
240
|
+
Foo = Class.new
|
241
|
+
subject.ref(Foo)
|
242
|
+
def Foo.foo; "baz"; end
|
243
|
+
subject.eval(%|Foo.foo|).should == "baz"
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should be possible to dynamically add a class method after the ref" do
|
247
|
+
Foo = Class.new
|
248
|
+
subject.ref(Foo)
|
249
|
+
Foo.class_eval(%|def Foo.foo; "baz"; end|)
|
250
|
+
subject.eval(%|Foo.foo|).should == "baz"
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should be possible to dynamically add a class method after the ref" do
|
254
|
+
Foo = Class.new
|
255
|
+
subject.ref(Foo)
|
256
|
+
Foo.instance_eval(%|def Foo.foo; "baz"; end|)
|
257
|
+
subject.eval(%|Foo.foo|).should == "baz"
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should be possible to call a method on the class that receives a block" do
|
261
|
+
Foo = Class.new do
|
262
|
+
def self.bar
|
263
|
+
yield
|
264
|
+
end
|
265
|
+
end
|
266
|
+
subject.ref(Foo)
|
267
|
+
subject.eval(%|Foo.bar { "baz" }|).should == "baz"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
foo
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xplenty-jruby_sandbox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.4
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Dray Lacy
|
8
|
+
- Eric Allam
|
9
|
+
- Moty Michaely
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2017-07-03 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: fakefs
|
17
|
+
version_requirements: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
prerelease: false
|
28
|
+
type: :runtime
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
version_requirements: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
prerelease: false
|
42
|
+
type: :development
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rake-compiler
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
prerelease: false
|
56
|
+
type: :development
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rspec
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
prerelease: false
|
70
|
+
type: :development
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: yard
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
prerelease: false
|
84
|
+
type: :development
|
85
|
+
description: A version of _why's Freaky Freaky Sandbox for JRuby.
|
86
|
+
email:
|
87
|
+
- dray@envylabs.com
|
88
|
+
- eric@envylabs.com
|
89
|
+
- moty.mi@gmail.com
|
90
|
+
executables: []
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- .gitignore
|
95
|
+
- .ruby-version
|
96
|
+
- .travis.yml
|
97
|
+
- CHANGELOG.md
|
98
|
+
- Gemfile
|
99
|
+
- LICENSE
|
100
|
+
- README.md
|
101
|
+
- Rakefile
|
102
|
+
- ext/java/sandbox/BoxedClass.java
|
103
|
+
- ext/java/sandbox/SandboxFull.java
|
104
|
+
- ext/java/sandbox/SandboxModule.java
|
105
|
+
- ext/java/sandbox/SandboxProfile.java
|
106
|
+
- ext/java/sandbox/SandboxService.java
|
107
|
+
- jruby_sandbox.gemspec
|
108
|
+
- lib/sandbox.rb
|
109
|
+
- lib/sandbox/prelude.rb
|
110
|
+
- lib/sandbox/safe.rb
|
111
|
+
- lib/sandbox/version.rb
|
112
|
+
- spec/exploits_spec.rb
|
113
|
+
- spec/sandbox_spec.rb
|
114
|
+
- spec/support/foo.txt
|
115
|
+
- lib/sandbox/sandbox.jar
|
116
|
+
homepage: http://github.com/xplenty/jruby-sandbox
|
117
|
+
licenses: []
|
118
|
+
metadata: {}
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubyforge_project: jruby_sandbox
|
135
|
+
rubygems_version: 2.1.9
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: Sandbox support for JRuby
|
139
|
+
test_files: []
|