shikashi-the-north 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/AUTHORS +8 -0
- data/CHANGELOG +45 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/README +222 -0
- data/Rakefile +40 -0
- data/TODO +2 -0
- data/examples/basic/example.rb +29 -0
- data/examples/basic/example1.rb +12 -0
- data/examples/basic/example2.rb +24 -0
- data/examples/basic/example3.rb +43 -0
- data/examples/basic/example4.rb +33 -0
- data/examples/basic/example5.rb +38 -0
- data/examples/basic/example6.rb +16 -0
- data/examples/basic/example7.rb +15 -0
- data/examples/basic/example8.rb +29 -0
- data/examples/benchmark/bm1.rb +29 -0
- data/examples/benchmark/bm2.rb +25 -0
- data/examples/timeout/example1.rb +9 -0
- data/lib/shikashi.rb +23 -0
- data/lib/shikashi/pick_argument.rb +81 -0
- data/lib/shikashi/privileges.rb +418 -0
- data/lib/shikashi/privileges/classes.rb +29 -0
- data/lib/shikashi/privileges/exceptions.rb +29 -0
- data/lib/shikashi/privileges/singleton_methods.rb +29 -0
- data/lib/shikashi/sandbox.rb +530 -0
- data/shikashi.gemspec +23 -0
- data/spec/functional/encoding_spec.rb +39 -0
- data/spec/functional/timeout_spec.rb +57 -0
- data/spec/sandbox/privileges_sugar_syntax_spec.rb +160 -0
- data/spec/sandbox/sandbox_hook_handler_spec.rb +181 -0
- data/spec/sandbox/sandbox_spec.rb +331 -0
- data/spec/sandbox/sugar_syntax_spec.rb +36 -0
- data/spec/security/system_calls_spec.rb +59 -0
- metadata +117 -0
data/shikashi.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "shikashi-the-north"
|
7
|
+
gem.version = '0.1'
|
8
|
+
|
9
|
+
gem.files = `git ls-files`.split($/)
|
10
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
11
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
12
|
+
gem.require_paths = ["lib"]
|
13
|
+
|
14
|
+
gem.authors = ["Joey Perira", "Adam Williams"]
|
15
|
+
gem.email = ["joey@pereira.io"]
|
16
|
+
gem.summary = %q{Shikashi is a ruby sandbox for running arbitrary Ruby code with eval.}
|
17
|
+
gem.description = %q{Shikashi allows whitelisting specific language features, from constants, to system modules, to arbitrary functions. This allows compete control over what evaluated code can do, restricting use outside of specification. WARNING: changes made in this package are experimental and can cause security flaws at the gain of performance.}
|
18
|
+
gem.homepage = "https://github.com/xLegoz/shikashi"
|
19
|
+
# gem.license = 'MIT'
|
20
|
+
|
21
|
+
gem.add_dependency 'evalhook', '~> 0.6.0'
|
22
|
+
gem.add_dependency 'getsource', '~> 0.2.2'
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "test/unit"
|
3
|
+
require "shikashi"
|
4
|
+
|
5
|
+
include Shikashi
|
6
|
+
|
7
|
+
describe Sandbox, "Shikashi sandbox" do
|
8
|
+
it "Should accept UTF-8 encoding via ruby header comments" do
|
9
|
+
Sandbox.new.run("# encoding: utf-8\n'кириллица'").should be == 'кириллица'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Should accept UTF-8 encoding via sandbox run options" do
|
13
|
+
Sandbox.new.run("'кириллица'", :encoding => "utf-8").should be == 'кириллица'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "Should accept UTF-8 encoding via ruby header comments" do
|
17
|
+
Sandbox.new.run("# encoding: utf-8\n'кириллица'").should be == 'кириллица'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Should accept UTF-8 encoding via ruby header comments" do
|
21
|
+
Sandbox.new.run("# encoding: utf-8\n'кириллица'").should be == 'кириллица'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "Should accept UTF-8 encoding via ruby header comments" do
|
25
|
+
Sandbox.new.packet("# encoding: utf-8\n'кириллица'").run.should be == 'кириллица'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "Should accept UTF-8 encoding via sandbox run options" do
|
29
|
+
Sandbox.new.packet("'кириллица'", :encoding => "utf-8").run.should be == 'кириллица'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "Should accept UTF-8 encoding via ruby header comments" do
|
33
|
+
Sandbox.new.packet("# encoding: utf-8\n'кириллица'").run.should be == 'кириллица'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "Should accept UTF-8 encoding via ruby header comments" do
|
37
|
+
Sandbox.new.packet("# encoding: utf-8\n'кириллица'").run.should be == 'кириллица'
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the shikashi project, http://github.com/tario/shikashi
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
shikashi is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
shikashi is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with shikashi. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "test/unit"
|
22
|
+
require "shikashi"
|
23
|
+
|
24
|
+
include Shikashi
|
25
|
+
|
26
|
+
describe Sandbox, "Shikashi sandbox" do
|
27
|
+
|
28
|
+
def self.add_test(name, execution_delay, timeout)
|
29
|
+
if execution_delay > timeout
|
30
|
+
it "Should allow timeout of type #{name}" do
|
31
|
+
priv = Shikashi::Privileges.new
|
32
|
+
priv.allow_method :sleep
|
33
|
+
|
34
|
+
lambda {
|
35
|
+
Sandbox.new.run "sleep #{execution_delay}", priv, :timeout => timeout
|
36
|
+
}.should raise_error(Shikashi::Timeout::Error)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
it "Should allow timeout of type #{name}" do
|
40
|
+
priv = Shikashi::Privileges.new
|
41
|
+
priv.allow_method :sleep
|
42
|
+
|
43
|
+
Sandbox.new.run "sleep #{execution_delay}", priv, :timeout => timeout
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
add_test "basic",2,1
|
51
|
+
add_test "float",0.2,0.1
|
52
|
+
add_test "float_no_hit",0.1,0.2
|
53
|
+
add_test "zero", 1,0
|
54
|
+
add_test "zero_no_hit", 0,1
|
55
|
+
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require "shikashi"
|
2
|
+
|
3
|
+
include Shikashi
|
4
|
+
|
5
|
+
describe Privileges, "Shikashi::Privileges" do
|
6
|
+
|
7
|
+
# method chaining
|
8
|
+
it "allow_method should return object of Privileges class" do
|
9
|
+
Privileges.allow_method(:foo).should be_kind_of(Privileges)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "allow_global_read should return object of Privileges class" do
|
13
|
+
Privileges.allow_global_read(:$a).should be_kind_of(Privileges)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "allow_global_write should return object of Privileges class" do
|
17
|
+
Privileges.allow_global_write(:$a).should be_kind_of(Privileges)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "allow_const_read should return object of Privileges class" do
|
21
|
+
Privileges.allow_const_read(:$a).should be_kind_of(Privileges)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "allow_const_write should return object of Privileges class" do
|
25
|
+
Privileges.allow_const_write(:$a).should be_kind_of(Privileges)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "allow_xstr should return object of Privileges class" do
|
29
|
+
Privileges.allow_xstr.should be_kind_of(Privileges)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "instances_of(...).allow() should return object of Privileges class" do
|
33
|
+
Privileges.instances_of(Fixnum).allow("foo").should be_kind_of(Privileges)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "object(...).allow() should return object of Privileges class" do
|
37
|
+
Privileges.object(Fixnum).allow("foo").should be_kind_of(Privileges)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "methods_of(...).allow() should return object of Privileges class" do
|
41
|
+
Privileges.methods_of(Fixnum).allow("foo").should be_kind_of(Privileges)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "instances_of(...).allow() should return object of Privileges class" do
|
45
|
+
Privileges.instances_of(Fixnum).allow_all.should be_kind_of(Privileges)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "object(...).allow() should return object of Privileges class" do
|
49
|
+
Privileges.object(Fixnum).allow_all.should be_kind_of(Privileges)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "methods_of(...).allow() should return object of Privileges class" do
|
53
|
+
Privileges.methods_of(Fixnum).allow_all.should be_kind_of(Privileges)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should chain one allow_method" do
|
57
|
+
priv = Privileges.allow_method(:to_s)
|
58
|
+
priv.allow?(Fixnum,4,:to_s,0).should be == true
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should chain one allow_method and one allow_global" do
|
62
|
+
priv = Privileges.
|
63
|
+
allow_method(:to_s).
|
64
|
+
allow_global_read(:$a)
|
65
|
+
|
66
|
+
priv.allow?(Fixnum,4,:to_s,0).should be == true
|
67
|
+
priv.global_read_allowed?(:$a).should be == true
|
68
|
+
end
|
69
|
+
|
70
|
+
# argument conversion
|
71
|
+
it "should allow + method (as string)" do
|
72
|
+
priv = Privileges.new
|
73
|
+
priv.allow_method("+")
|
74
|
+
priv.allow?(Fixnum,4,:+,0).should be == true
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should allow + method (as symbol)" do
|
78
|
+
priv = Privileges.new
|
79
|
+
priv.allow_method(:+)
|
80
|
+
priv.allow?(Fixnum,4,:+,0).should be == true
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should allow $a global read (as string)" do
|
84
|
+
priv = Privileges.new
|
85
|
+
priv.allow_global_read("$a")
|
86
|
+
priv.global_read_allowed?(:$a).should be == true
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should allow $a global read (as symbol)" do
|
90
|
+
priv = Privileges.new
|
91
|
+
priv.allow_global_read(:$a)
|
92
|
+
priv.global_read_allowed?(:$a).should be == true
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should allow multiple global read (as symbol) in only one allow_global_read call" do
|
96
|
+
priv = Privileges.new
|
97
|
+
priv.allow_global_read(:$a, :$b)
|
98
|
+
priv.global_read_allowed?(:$a).should be == true
|
99
|
+
priv.global_read_allowed?(:$b).should be == true
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should allow $a global write (as string)" do
|
103
|
+
priv = Privileges.new
|
104
|
+
priv.allow_global_write("$a")
|
105
|
+
priv.global_write_allowed?(:$a).should be == true
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should allow $a global write (as symbol)" do
|
109
|
+
priv = Privileges.new
|
110
|
+
priv.allow_global_write(:$a)
|
111
|
+
priv.global_write_allowed?(:$a).should be == true
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should allow multiple global write (as symbol) in only one allow_global_write call" do
|
115
|
+
priv = Privileges.new
|
116
|
+
priv.allow_global_write(:$a, :$b)
|
117
|
+
priv.global_write_allowed?(:$a).should be == true
|
118
|
+
priv.global_write_allowed?(:$b).should be == true
|
119
|
+
end
|
120
|
+
|
121
|
+
# constants
|
122
|
+
|
123
|
+
it "should allow constant read (as string)" do
|
124
|
+
priv = Privileges.new
|
125
|
+
priv.allow_const_read("TESTCONSTANT")
|
126
|
+
priv.const_read_allowed?("TESTCONSTANT").should be == true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should allow constant read (as symbol)" do
|
130
|
+
priv = Privileges.new
|
131
|
+
priv.allow_const_read(:TESTCONSTANT)
|
132
|
+
priv.const_read_allowed?("TESTCONSTANT").should be == true
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should allow multiple constant read (as string) in only one allow_const_read call" do
|
136
|
+
priv = Privileges.new
|
137
|
+
priv.allow_const_read("TESTCONSTANT1", "TESTCONSTANT2")
|
138
|
+
priv.const_read_allowed?("TESTCONSTANT1").should be == true
|
139
|
+
priv.const_read_allowed?("TESTCONSTANT2").should be == true
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should allow constant write (as string)" do
|
143
|
+
priv = Privileges.new
|
144
|
+
priv.allow_const_write("TESTCONSTANT")
|
145
|
+
priv.const_write_allowed?("TESTCONSTANT").should be == true
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should allow constant write (as symbol)" do
|
149
|
+
priv = Privileges.new
|
150
|
+
priv.allow_const_write(:TESTCONSTANT)
|
151
|
+
priv.const_write_allowed?("TESTCONSTANT").should be == true
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should allow multiple constant write (as symbol) in only one allow_const_write call" do
|
155
|
+
priv = Privileges.new
|
156
|
+
priv.allow_const_write("TESTCONSTANT1", "TESTCONSTANT2")
|
157
|
+
priv.const_write_allowed?("TESTCONSTANT1").should be == true
|
158
|
+
priv.const_write_allowed?("TESTCONSTANT2").should be == true
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "shikashi"
|
3
|
+
require "evalhook"
|
4
|
+
|
5
|
+
include Shikashi
|
6
|
+
|
7
|
+
describe Sandbox, "Shikashi sandbox hook handler" do
|
8
|
+
|
9
|
+
it "should be obtainable from sandbox" do
|
10
|
+
Sandbox.new.hook_handler
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be obtainable from sandbox through create_hook_handler" do
|
14
|
+
sandbox = Sandbox.new
|
15
|
+
hook_handler = sandbox.create_hook_handler()
|
16
|
+
hook_handler.should be_kind_of(EvalHook::HookHandler)
|
17
|
+
end
|
18
|
+
|
19
|
+
class X
|
20
|
+
def foo
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
it "should raise SecurityError when handle calls without privileges" do
|
25
|
+
sandbox = Sandbox.new
|
26
|
+
hook_handler = sandbox.create_hook_handler()
|
27
|
+
|
28
|
+
x = X.new
|
29
|
+
lambda {
|
30
|
+
hook_handler.handle_method(X,x,:foo)
|
31
|
+
}.should raise_error(SecurityError)
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not raise SecurityError with method privileges" do
|
36
|
+
sandbox = Sandbox.new
|
37
|
+
priv = Privileges.new
|
38
|
+
priv.allow_method(:foo)
|
39
|
+
|
40
|
+
hook_handler = sandbox.create_hook_handler(:privileges => priv, :source => "test-source")
|
41
|
+
|
42
|
+
def hook_handler.get_caller
|
43
|
+
"test-source"
|
44
|
+
end
|
45
|
+
|
46
|
+
x = X.new
|
47
|
+
lambda {
|
48
|
+
hook_handler.handle_method(X,x,:foo)
|
49
|
+
|
50
|
+
}.should_not raise_error
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should raise SecurityError with handle_gasgn without privileges" do
|
55
|
+
sandbox = Sandbox.new
|
56
|
+
|
57
|
+
hook_handler = sandbox.create_hook_handler(:source => "test-source")
|
58
|
+
|
59
|
+
def hook_handler.get_caller
|
60
|
+
"test-source"
|
61
|
+
end
|
62
|
+
|
63
|
+
lambda {
|
64
|
+
hook_handler.handle_gasgn(:$a,nil)
|
65
|
+
}.should raise_error(SecurityError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should not raise SecurityError with handle_gasgn with privileges" do
|
69
|
+
sandbox = Sandbox.new
|
70
|
+
privileges = Privileges.new
|
71
|
+
|
72
|
+
privileges.allow_global_write(:$a)
|
73
|
+
|
74
|
+
hook_handler = sandbox.create_hook_handler(:privileges => privileges, :source => "test-source")
|
75
|
+
|
76
|
+
def hook_handler.get_caller
|
77
|
+
"test-source"
|
78
|
+
end
|
79
|
+
|
80
|
+
lambda {
|
81
|
+
hook_handler.handle_gasgn(:$a,nil)
|
82
|
+
}.should_not raise_error
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should raise SecurityError with handle_cdecl without privileges" do
|
86
|
+
sandbox = Sandbox.new
|
87
|
+
|
88
|
+
hook_handler = sandbox.create_hook_handler(:source => "test-source")
|
89
|
+
|
90
|
+
def hook_handler.get_caller
|
91
|
+
"test-source"
|
92
|
+
end
|
93
|
+
|
94
|
+
lambda {
|
95
|
+
hook_handler.handle_cdecl(Object,:A,nil)
|
96
|
+
}.should raise_error(SecurityError)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should not raise SecurityError with handle_cdecl with privileges" do
|
100
|
+
sandbox = Sandbox.new
|
101
|
+
privileges = Privileges.new
|
102
|
+
|
103
|
+
privileges.allow_const_write("Object::A")
|
104
|
+
|
105
|
+
hook_handler = sandbox.create_hook_handler(:privileges => privileges, :source => "test-source")
|
106
|
+
|
107
|
+
def hook_handler.get_caller
|
108
|
+
"test-source"
|
109
|
+
end
|
110
|
+
|
111
|
+
lambda {
|
112
|
+
hook_handler.handle_cdecl(Object,:A,nil)
|
113
|
+
}.should_not raise_error
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
it "should raise SecurityError with handle_gvar without privileges" do
|
119
|
+
sandbox = Sandbox.new
|
120
|
+
|
121
|
+
hook_handler = sandbox.create_hook_handler(:source => "test-source")
|
122
|
+
|
123
|
+
def hook_handler.get_caller
|
124
|
+
"test-source"
|
125
|
+
end
|
126
|
+
|
127
|
+
lambda {
|
128
|
+
hook_handler.handle_gvar(:$a)
|
129
|
+
}.should raise_error(SecurityError)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should not raise SecurityError with handle_gasgn with privileges" do
|
133
|
+
sandbox = Sandbox.new
|
134
|
+
privileges = Privileges.new
|
135
|
+
|
136
|
+
privileges.allow_global_read(:$a)
|
137
|
+
|
138
|
+
hook_handler = sandbox.create_hook_handler(:privileges => privileges, :source => "test-source")
|
139
|
+
|
140
|
+
def hook_handler.get_caller
|
141
|
+
"test-source"
|
142
|
+
end
|
143
|
+
|
144
|
+
lambda {
|
145
|
+
hook_handler.handle_gvar(:$a)
|
146
|
+
}.should_not raise_error
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should raise SecurityError with handle_const without privileges" do
|
150
|
+
sandbox = Sandbox.new
|
151
|
+
|
152
|
+
hook_handler = sandbox.create_hook_handler(:source => "test-source")
|
153
|
+
|
154
|
+
def hook_handler.get_caller
|
155
|
+
"test-source"
|
156
|
+
end
|
157
|
+
|
158
|
+
lambda {
|
159
|
+
hook_handler.handle_const(:A)
|
160
|
+
}.should raise_error(SecurityError)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should not raise SecurityError with handle_cdecl with privileges" do
|
164
|
+
sandbox = Sandbox.new
|
165
|
+
privileges = Privileges.new
|
166
|
+
|
167
|
+
::A = nil
|
168
|
+
privileges.allow_const_read("A")
|
169
|
+
|
170
|
+
hook_handler = sandbox.create_hook_handler(:privileges => privileges, :source => "test-source")
|
171
|
+
|
172
|
+
def hook_handler.get_caller
|
173
|
+
"test-source"
|
174
|
+
end
|
175
|
+
|
176
|
+
lambda {
|
177
|
+
hook_handler.handle_const(:A)
|
178
|
+
}.should_not raise_error
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|