shikashi 0.1.0
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.
- data/AUTHORS +3 -0
- data/CHANGELOG +1 -0
- data/README +199 -0
- data/Rakefile +48 -0
- data/TODO +0 -0
- data/examples/basic/example.rb +28 -0
- data/examples/basic/example1.rb +12 -0
- data/examples/basic/example2.rb +24 -0
- data/examples/basic/example3.rb +46 -0
- data/examples/basic/example4.rb +41 -0
- data/examples/basic/example5.rb +40 -0
- data/lib/shikashi.rb +23 -0
- data/lib/shikashi/pick_argument.rb +81 -0
- data/lib/shikashi/privileges.rb +294 -0
- data/lib/shikashi/privileges/classes.rb +28 -0
- data/lib/shikashi/privileges/exceptions.rb +29 -0
- data/lib/shikashi/privileges/singleton_methods.rb +28 -0
- data/lib/shikashi/sandbox.rb +381 -0
- metadata +81 -0
data/AUTHORS
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0 Optimized Cymbol::resolv by using a singleton of Cymbol::Resolv
|
data/README
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
= Shikashi - A flexible sandbox for ruby
|
2
|
+
|
3
|
+
Shikashi is an sandbox for ruby that handles all ruby method calls executed in the interpreter to allow or deny
|
4
|
+
these calls depending on the receiver object, the method name, the source file from where the call was originated
|
5
|
+
and the source file where the called method is implemented.
|
6
|
+
|
7
|
+
The permissions for each sandboxed run is fully configurable and the implementation of the methods called from
|
8
|
+
the sandbox can be replaced transparently (i.e: replace method IO#write in the sandbox context to capture the
|
9
|
+
standard output of the script)
|
10
|
+
|
11
|
+
The implementation of shikashi is pure ruby and it is based on rallhook, an amending of the ruby interpreter
|
12
|
+
(see http://tario.github.com/rallhook/doc)
|
13
|
+
|
14
|
+
== Installation
|
15
|
+
|
16
|
+
=== Prerequisites
|
17
|
+
|
18
|
+
* rallhook >= 0.7.0 (found at http://github.com/tario/rallhook)
|
19
|
+
|
20
|
+
=== Gem installation
|
21
|
+
|
22
|
+
* Download the last version of the gem from http://github.com/tario/shikashi/downloads
|
23
|
+
* Install the gem with the following;
|
24
|
+
|
25
|
+
gem install shikashi-X.X.X.gem.
|
26
|
+
|
27
|
+
== Documentation
|
28
|
+
|
29
|
+
Full API documentation can be found on:
|
30
|
+
http://tario.github.com/shikashi/doc/
|
31
|
+
|
32
|
+
== Usage
|
33
|
+
|
34
|
+
This examples and more can be found in examples directory
|
35
|
+
|
36
|
+
=== Basic Example
|
37
|
+
|
38
|
+
Hello world from a sandbox
|
39
|
+
|
40
|
+
require "rubygems"
|
41
|
+
require "shikashi"
|
42
|
+
|
43
|
+
include Shikashi
|
44
|
+
|
45
|
+
s = Sandbox.new
|
46
|
+
priv = Privileges.new
|
47
|
+
priv.allow_method :print
|
48
|
+
|
49
|
+
s.run(priv, 'print "hello world\n"')
|
50
|
+
|
51
|
+
=== Basic Example 2
|
52
|
+
|
53
|
+
Call external method from inside the sandbox
|
54
|
+
|
55
|
+
require "rubygems"
|
56
|
+
require "shikashi"
|
57
|
+
|
58
|
+
include Shikashi
|
59
|
+
|
60
|
+
def foo
|
61
|
+
# privileged code, can do any operation
|
62
|
+
print "foo\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
s = Sandbox.new
|
66
|
+
priv = Privileges.new
|
67
|
+
|
68
|
+
# allow execution of foo in this object
|
69
|
+
priv.object(self).allow :foo
|
70
|
+
|
71
|
+
# allow execution of method :times on instances of Fixnum
|
72
|
+
priv.instances_of(Fixnum).allow :times
|
73
|
+
|
74
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
75
|
+
s.run(priv, "2.times do foo end")
|
76
|
+
|
77
|
+
=== Basic Example 3
|
78
|
+
|
79
|
+
Define a class outside the sandbox and use it in the sandbox
|
80
|
+
|
81
|
+
require "rubygems"
|
82
|
+
require "shikashi"
|
83
|
+
|
84
|
+
include Shikashi
|
85
|
+
|
86
|
+
s = Sandbox.new
|
87
|
+
priv = Privileges.new
|
88
|
+
|
89
|
+
# allow execution of print
|
90
|
+
priv.allow_method :print
|
91
|
+
|
92
|
+
class X
|
93
|
+
def foo
|
94
|
+
print "X#foo\n"
|
95
|
+
end
|
96
|
+
|
97
|
+
def bar
|
98
|
+
system("echo hello world") # accepted, called from privileged context
|
99
|
+
end
|
100
|
+
|
101
|
+
def privileged_operation( out )
|
102
|
+
# write to file specified in out
|
103
|
+
system("echo privileged operation > " + out)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
# allow method new of class X
|
107
|
+
priv.object(X).allow :new
|
108
|
+
|
109
|
+
# allow instance methods of X. Note that the method privileged_operations is not allowed
|
110
|
+
priv.instances_of(X).allow :foo, :bar
|
111
|
+
|
112
|
+
priv.allow_method :=== # for exception handling
|
113
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
114
|
+
s.run(priv, '
|
115
|
+
x = X.new
|
116
|
+
x.foo
|
117
|
+
x.bar
|
118
|
+
|
119
|
+
begin
|
120
|
+
x.privileged_operation # FAIL
|
121
|
+
rescue SecurityError
|
122
|
+
print "privileged_operation failed due security error\n"
|
123
|
+
end
|
124
|
+
')
|
125
|
+
|
126
|
+
=== Basic Example 4
|
127
|
+
|
128
|
+
define a class from inside the sandbox and use it from outside
|
129
|
+
|
130
|
+
require "rubygems"
|
131
|
+
require "shikashi"
|
132
|
+
|
133
|
+
include Shikashi
|
134
|
+
|
135
|
+
s = Sandbox.new
|
136
|
+
priv = Privileges.new
|
137
|
+
|
138
|
+
# allow execution of print
|
139
|
+
priv.allow_method :print
|
140
|
+
|
141
|
+
# allow definition of classes
|
142
|
+
priv.allow_class_definitions
|
143
|
+
|
144
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
145
|
+
s.run(priv, '
|
146
|
+
class X
|
147
|
+
def foo
|
148
|
+
print "X#foo\n"
|
149
|
+
end
|
150
|
+
|
151
|
+
def bar
|
152
|
+
system("ls -l")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
')
|
156
|
+
|
157
|
+
# run privileged code in the sandbox, if not, the methods defined in the sandbox are invisible from outside
|
158
|
+
s.run do
|
159
|
+
x = X.new
|
160
|
+
x.foo
|
161
|
+
begin
|
162
|
+
x.bar
|
163
|
+
rescue SecurityError => e
|
164
|
+
print "x.bar failed due security errors: #{e}\n"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
=== Redirection feature example
|
170
|
+
|
171
|
+
Simple redirection of method, the method foo is replaced by TestWrapper::call
|
172
|
+
|
173
|
+
require "rubygems"
|
174
|
+
require "shikashi"
|
175
|
+
|
176
|
+
class TestWrapper < Shikashi::Sandbox::MethodWrapper
|
177
|
+
def call(*args)
|
178
|
+
print "called foo from source: #{source}, arguments: #{args.inspect} \n"
|
179
|
+
original_call(*args)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class X
|
184
|
+
def foo
|
185
|
+
print "original foo\n"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
s = Shikashi::Sandbox.new
|
190
|
+
perm = Shikashi::Privileges.new
|
191
|
+
|
192
|
+
perm.object(X).allow :new
|
193
|
+
perm.instances_of(X).allow :foo
|
194
|
+
|
195
|
+
# redirect calls to foo to TestWrapper
|
196
|
+
perm.instances_of(X).redirect :foo, TestWrapper
|
197
|
+
|
198
|
+
s.run(perm,"X.new.foo")
|
199
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'shikashi'
|
9
|
+
s.version = '0.1.0'
|
10
|
+
s.author = 'Dario Seminara'
|
11
|
+
s.email = 'robertodarioseminara@gmail.com'
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.summary = 'shikashi is a ruby sandbox that permits the execution of "unprivileged" scripts by defining the permitted methods and constants the scripts can invoke (I.E., the script cannot use the File class or a RoR Model Class unless that permission is specified) "well done version" of ruby-arena-sanbox based on rallhook'
|
14
|
+
s.homepage = "http://github.com/tario/shikashi"
|
15
|
+
s.add_dependency "rallhook", ">= 0.7.0"
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = [ 'README' ]
|
18
|
+
# s.rdoc_options << '--main' << 'README'
|
19
|
+
s.files = Dir.glob("{examples,lib,test}/**/*") +
|
20
|
+
[ 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Run tests'
|
24
|
+
task :default => [ :test ]
|
25
|
+
|
26
|
+
Rake::TestTask.new('test') do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = '{test}/test_*.rb'
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Generate RDoc'
|
33
|
+
Rake::RDocTask.new :rdoc do |rd|
|
34
|
+
rd.rdoc_dir = 'doc'
|
35
|
+
rd.rdoc_files.add 'lib', 'README'
|
36
|
+
rd.main = 'README'
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Build Gem'
|
40
|
+
Rake::GemPackageTask.new spec do |pkg|
|
41
|
+
pkg.need_tar = true
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Clean up'
|
45
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
46
|
+
|
47
|
+
desc 'Clean up'
|
48
|
+
task :clobber => [ :clean ]
|
data/TODO
ADDED
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# call method defined in sandbox from outside
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "shikashi"
|
5
|
+
|
6
|
+
include Shikashi
|
7
|
+
|
8
|
+
s = Sandbox.new
|
9
|
+
priv = Privileges.new
|
10
|
+
|
11
|
+
# allow execution of foo in this object
|
12
|
+
priv.object(self).allow :foo
|
13
|
+
|
14
|
+
# allow execution of print in this object
|
15
|
+
priv.object(self).allow :print
|
16
|
+
|
17
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
18
|
+
s.run(priv, "
|
19
|
+
def inside_foo(a)
|
20
|
+
print 'inside_foo'
|
21
|
+
if (a)
|
22
|
+
system('ls -l') # denied
|
23
|
+
end
|
24
|
+
end
|
25
|
+
")
|
26
|
+
|
27
|
+
inside_foo(false)
|
28
|
+
inside_foo(true)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# call external method from inside the sandbox
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "shikashi"
|
5
|
+
|
6
|
+
include Shikashi
|
7
|
+
|
8
|
+
def foo
|
9
|
+
# privileged code, can do any operation
|
10
|
+
print "foo\n"
|
11
|
+
end
|
12
|
+
|
13
|
+
s = Sandbox.new
|
14
|
+
priv = Privileges.new
|
15
|
+
|
16
|
+
# allow execution of foo in this object
|
17
|
+
priv.object(self).allow :foo
|
18
|
+
|
19
|
+
# allow execution of method :times on instances of Fixnum
|
20
|
+
priv.instances_of(Fixnum).allow :times
|
21
|
+
|
22
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
23
|
+
s.run(priv, "2.times do foo end")
|
24
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# define a class outside the sandbox and use it in the sandbox
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "shikashi"
|
5
|
+
|
6
|
+
include Shikashi
|
7
|
+
|
8
|
+
s = Sandbox.new
|
9
|
+
priv = Privileges.new
|
10
|
+
|
11
|
+
# allow execution of print
|
12
|
+
priv.allow_method :print
|
13
|
+
|
14
|
+
class X
|
15
|
+
def foo
|
16
|
+
print "X#foo\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def bar
|
20
|
+
system("echo hello world") # accepted, called from privileged context
|
21
|
+
end
|
22
|
+
|
23
|
+
def privileged_operation( out )
|
24
|
+
# write to file specified in out
|
25
|
+
system("echo privileged operation > " + out)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# allow method new of class X
|
29
|
+
priv.object(X).allow :new
|
30
|
+
|
31
|
+
# allow instance methods of X. Note that the method privileged_operations is not allowed
|
32
|
+
priv.instances_of(X).allow :foo, :bar
|
33
|
+
|
34
|
+
priv.allow_method :=== # for exception handling
|
35
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
36
|
+
s.run(priv, '
|
37
|
+
x = X.new
|
38
|
+
x.foo
|
39
|
+
x.bar
|
40
|
+
|
41
|
+
begin
|
42
|
+
x.privileged_operation # FAIL
|
43
|
+
rescue SecurityError
|
44
|
+
print "privileged_operation failed due security error\n"
|
45
|
+
end
|
46
|
+
')
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# call method defined in sandbox from outside
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "shikashi"
|
5
|
+
|
6
|
+
include Shikashi
|
7
|
+
|
8
|
+
s = Sandbox.new
|
9
|
+
priv = Privileges.new
|
10
|
+
|
11
|
+
# allow execution of print
|
12
|
+
priv.allow_method :print
|
13
|
+
|
14
|
+
# allow execution of method_added
|
15
|
+
priv.allow_method :method_added
|
16
|
+
|
17
|
+
# allow execution of singleton_method_added
|
18
|
+
priv.allow_method :singleton_method_added
|
19
|
+
|
20
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
21
|
+
s.run(priv, '
|
22
|
+
module A
|
23
|
+
def self.inside_foo(a)
|
24
|
+
print "inside_foo\n"
|
25
|
+
if (a)
|
26
|
+
system("ls -l") # denied
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
')
|
31
|
+
|
32
|
+
# run privileged code in the sandbox, if not, the methods defined in the sandbox are invisible from outside
|
33
|
+
s.run do
|
34
|
+
A.inside_foo(false)
|
35
|
+
begin
|
36
|
+
A.inside_foo(true)
|
37
|
+
rescue SecurityError => e
|
38
|
+
print "A.inside_foo(true) failed due security errors: #{e}\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# define a class from inside the sandbox and use it from outside
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "shikashi"
|
5
|
+
|
6
|
+
include Shikashi
|
7
|
+
|
8
|
+
s = Sandbox.new
|
9
|
+
priv = Privileges.new
|
10
|
+
|
11
|
+
# allow execution of print
|
12
|
+
priv.allow_method :print
|
13
|
+
|
14
|
+
# allow definition of classes
|
15
|
+
priv.allow_class_definitions
|
16
|
+
|
17
|
+
#inside the sandbox, only can use method foo on main and method times on instances of Fixnum
|
18
|
+
s.run(priv, '
|
19
|
+
class X
|
20
|
+
def foo
|
21
|
+
print "X#foo\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def bar
|
25
|
+
system("ls -l")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
')
|
29
|
+
|
30
|
+
# run privileged code in the sandbox, if not, the methods defined in the sandbox are invisible from outside
|
31
|
+
s.run do
|
32
|
+
x = X.new
|
33
|
+
x.foo
|
34
|
+
begin
|
35
|
+
x.bar
|
36
|
+
rescue SecurityError => e
|
37
|
+
print "x.bar failed due security errors: #{e}\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|