shikashi 0.3.1 → 0.4.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/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ 0.4.0 Removed evalmimic dependency
2
+
3
+ Implemented sugar syntax for Sandbox and Privileges methods (see documentation)
4
+
5
+ Added control over READ access to constants
6
+
7
+ Added control over READ access to global variables
8
+
1
9
  0.3.1 Fixed package info
2
10
 
3
11
  0.3.0 Added enclosure by base_namespace parameter (see examples)
@@ -5,6 +13,8 @@
5
13
  shikashi HookHandler opened to allow use it in nested hook handlers
6
14
 
7
15
  Added restriction to avoid the system calls when using %x[] and ``
16
+
17
+ 0.2.0 shikashi HookHandler opened to allow use it in nested hook handlers
8
18
 
9
19
  0.2.0 Added control over the access to constants and global variables (See documentation)
10
20
 
data/Rakefile CHANGED
@@ -6,15 +6,14 @@ require 'rake/gempackagetask'
6
6
 
7
7
  spec = Gem::Specification.new do |s|
8
8
  s.name = 'shikashi'
9
- s.version = '0.3.1'
9
+ s.version = '0.4.0'
10
10
  s.author = 'Dario Seminara'
11
11
  s.email = 'robertodarioseminara@gmail.com'
12
12
  s.platform = Gem::Platform::RUBY
13
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 with a white list logic'
14
14
  s.homepage = "http://github.com/tario/shikashi"
15
- s.add_dependency "evalhook", ">= 0.2.0"
15
+ s.add_dependency "evalhook", ">= 0.4.0"
16
16
  s.add_dependency "getsource", ">= 0.1.0"
17
- s.add_dependency "evalmimic", ">= 0.1.0"
18
17
  s.has_rdoc = true
19
18
  s.extra_rdoc_files = [ 'README' ]
20
19
  # s.rdoc_options << '--main' << 'README'
@@ -6,10 +6,6 @@ require "shikashi"
6
6
  include Shikashi
7
7
 
8
8
  s = Sandbox.new
9
- priv = Privileges.new
10
-
11
- # allow execution of print
12
- priv.allow_method :print
13
9
 
14
10
  class X
15
11
  def foo
@@ -25,12 +21,14 @@ class X
25
21
  system("echo privileged operation > " + out)
26
22
  end
27
23
  end
28
- # allow method new of class X
29
- priv.object(X).allow :new
30
24
 
31
- # allow instance methods of X. Note that the method privileged_operations is not allowed
32
- priv.instances_of(X).allow :foo, :bar
33
25
 
26
+ priv = Privileges.
27
+ allow_method(:print). # allow execution of print
28
+ object(X).allow(:new). # allow method new of class X
29
+ instances_of(X).allow(:foo, :bar). # allow instance methods of X. Note that the method privileged_operations is not allowed
30
+ allow_const_read("X","SecurityError") # allow the access of X constant
31
+
34
32
  #inside the sandbox, only can use method foo on main and method times on instances of Fixnum
35
33
  s.run(priv, '
36
34
  x = X.new
@@ -5,15 +5,12 @@ require "shikashi"
5
5
 
6
6
  include Shikashi
7
7
 
8
- s = Sandbox.new
9
- priv = Privileges.new
10
-
11
- priv.allow_method :print
12
- priv.allow_global :$a
13
-
14
- s.run(priv, '
8
+ priv = Privileges.allow_method(:print).allow_global_write(:$a)
9
+ Sandbox.run(priv,
10
+ '
15
11
  $a = 9
16
12
  print "assigned 9 to $a\n"
17
- ')
13
+ '
14
+ )
18
15
 
19
16
  p $a
@@ -3,13 +3,11 @@ require "shikashi"
3
3
 
4
4
  include Shikashi
5
5
 
6
- s = Sandbox.new
7
- priv = Privileges.new
6
+ priv = Privileges.
7
+ allow_method(:print).
8
+ allow_const_write("Object::A")
8
9
 
9
- priv.allow_method :print
10
- priv.allow_const "Object::A"
11
-
12
- s.run(priv, '
10
+ Sandbox.run(priv, '
13
11
  print "assigned 8 to Object::A\n"
14
12
  A = 8
15
13
  ')
@@ -12,17 +12,13 @@ class X
12
12
  end
13
13
  end
14
14
 
15
- s = Sandbox.new
16
- priv = Privileges.new
17
- priv.allow_method :print
18
-
19
- s.run( "
15
+ Sandbox.new.run( "
20
16
  class ::X
21
17
  def foo
22
18
  print \"foo defined inside the sandbox\\n\"
23
19
  end
24
20
  end
25
- ", priv, :base_namespace => SandboxModule)
21
+ ", Privileges.allow_method(:print), :base_namespace => SandboxModule)
26
22
 
27
23
 
28
24
  x = X.new # X class is not affected by the sandbox (The X Class defined in the sandbox is SandboxModule::X)
@@ -40,7 +40,8 @@ public
40
40
 
41
41
  # Used in Privileges to store information about specified method permissions
42
42
  class AllowedMethods
43
- def initialize
43
+ def initialize(privileges = nil)
44
+ @privileges = privileges
44
45
  @allowed_methods = Array.new
45
46
  @redirect_hash = Hash.new
46
47
  @all = false
@@ -78,11 +79,15 @@ public
78
79
  method_names.each do |mn|
79
80
  @allowed_methods << mn
80
81
  end
82
+
83
+ @privileges
81
84
  end
82
85
 
83
86
  #Specifies that any method is allowed
84
87
  def allow_all
85
88
  @all = true
89
+
90
+ @privileges
86
91
  end
87
92
 
88
93
  end
@@ -94,15 +99,17 @@ public
94
99
  @allowed_instances = Hash.new
95
100
  @allowed_methods = Array.new
96
101
  @allowed_klass_methods = Hash.new
97
- @allowed_globals = Array.new
98
- @allowed_consts = Array.new
102
+ @allowed_read_globals = Array.new
103
+ @allowed_read_consts = Array.new
104
+ @allowed_write_globals = Array.new
105
+ @allowed_write_consts = Array.new
99
106
  end
100
107
 
101
108
  private
102
109
  def hash_entry(hash, key)
103
110
  tmp = hash[key]
104
111
  unless tmp
105
- tmp = AllowedMethods.new
112
+ tmp = AllowedMethods.new(self)
106
113
  hash[key] = tmp
107
114
  end
108
115
  tmp
@@ -168,7 +175,8 @@ public
168
175
  #
169
176
 
170
177
  def allow_method(method_name)
171
- @allowed_methods << method_name
178
+ @allowed_methods << method_name.to_sym
179
+ self
172
180
  end
173
181
 
174
182
  def allow?(klass, recv, method_name, method_id)
@@ -254,15 +262,23 @@ public
254
262
  @xstr_allowed
255
263
  end
256
264
 
257
- def global_allowed?(varname)
258
- @allowed_globals.include? varname
265
+ def global_read_allowed?(varname)
266
+ @allowed_read_globals.include? varname
267
+ end
268
+
269
+ def global_write_allowed?(varname)
270
+ @allowed_write_globals.include? varname
259
271
  end
260
272
 
261
- def const_allowed?(varname)
262
- @allowed_consts.include? varname
273
+ def const_read_allowed?(varname)
274
+ @allowed_read_consts.include? varname
263
275
  end
264
276
 
265
- # defines the permissions needed to execute system calls from the script
277
+ def const_write_allowed?(varname)
278
+ @allowed_write_consts.include? varname
279
+ end
280
+
281
+ # Enables the permissions needed to execute system calls from the script
266
282
  #
267
283
  # Example:
268
284
  #
@@ -274,11 +290,19 @@ public
274
290
  # s.run(priv, '
275
291
  # %x[ls -l]
276
292
  # ')
293
+ #
294
+ #
295
+ # Example 2:
296
+ #
297
+ # Sandbox.run('%x[ls -l]', Privileges.allow_xstr)
298
+ #
277
299
  def allow_xstr
278
300
  @xstr_allowed = true
301
+
302
+ self
279
303
  end
280
304
 
281
- # defines the permissions needed to create or change a global variable
305
+ # Enables the permissions needed to read one or more global variables
282
306
  #
283
307
  # Example:
284
308
  #
@@ -286,7 +310,38 @@ public
286
310
  # priv = Privileges.new
287
311
  #
288
312
  # priv.allow_method :print
289
- # priv.allow_global :$a
313
+ # priv.allow_global_read :$a
314
+ #
315
+ # $a = 9
316
+ #
317
+ # s.run(priv, '
318
+ # print "$a value:", $a, "s\n"
319
+ # ')
320
+ #
321
+ # Example 2
322
+ #
323
+ # Sandbox.run('
324
+ # print "$a value:", $a, "s\n"
325
+ # print "$b value:", $b, "s\n"
326
+ # ', Privileges.allow_global_read(:$a,:$b) )
327
+ #
328
+ def allow_global_read( *varnames )
329
+ varnames.each do |varname|
330
+ @allowed_read_globals << varname.to_sym
331
+ end
332
+
333
+ self
334
+ end
335
+
336
+ # Enables the permissions needed to create or change one or more global variables
337
+ #
338
+ # Example:
339
+ #
340
+ # s = Sandbox.new
341
+ # priv = Privileges.new
342
+ #
343
+ # priv.allow_method :print
344
+ # priv.allow_global_write :$a
290
345
  #
291
346
  # s.run(priv, '
292
347
  # $a = 9
@@ -295,18 +350,23 @@ public
295
350
  #
296
351
  # p $a
297
352
  #
298
- def allow_global( varname )
299
- @allowed_globals << varname
353
+ def allow_global_write( *varnames )
354
+ varnames.each do |varname|
355
+ @allowed_write_globals << varname.to_sym
356
+ end
357
+
358
+ self
300
359
  end
301
360
 
302
- # defines the permissions needed to create or change a const
361
+
362
+ # Enables the permissions needed to create or change one or more constants
303
363
  #
304
364
  # Example:
305
365
  # s = Sandbox.new
306
366
  # priv = Privileges.new
307
367
  #
308
368
  # priv.allow_method :print
309
- # priv.allow_const "Object::A"
369
+ # priv.allow_const_write "Object::A"
310
370
  #
311
371
  # s.run(priv, '
312
372
  # print "assigned 8 to Object::A\n"
@@ -315,10 +375,43 @@ public
315
375
  #
316
376
  # p A
317
377
 
318
- def allow_const( varname )
319
- @allowed_consts << varname
378
+ def allow_const_write( *varnames )
379
+ varnames.each do |varname|
380
+ @allowed_write_consts << varname.to_s
381
+ end
382
+ self
383
+ end
384
+
385
+ # Enables the permissions needed to read one or more constants
386
+ #
387
+ # Example:
388
+ # s = Sandbox.new
389
+ # priv = Privileges.new
390
+ #
391
+ # priv.allow_method :print
392
+ # priv.allow_const_read "Object::A"
393
+ #
394
+ # A = 8
395
+ # s.run(priv, '
396
+ # print "assigned Object::A:", A,"\n"
397
+ # ')
398
+ #
399
+ def allow_const_read( *varnames )
400
+ varnames.each do |varname|
401
+ @allowed_read_consts << varname.to_s
402
+ end
403
+
404
+ self
320
405
  end
321
406
 
407
+
408
+ class << self
409
+ (Shikashi::Privileges.instance_methods - Object.instance_methods).each do |mname|
410
+ define_method(mname) do |*args|
411
+ Shikashi::Privileges.new.send(mname, *args)
412
+ end
413
+ end
414
+ end
322
415
  end
323
416
 
324
417
  end
@@ -24,7 +24,6 @@ require "shikashi/privileges"
24
24
  require "shikashi/pick_argument"
25
25
  require "getsource"
26
26
  require "timeout"
27
- require "evalmimic"
28
27
 
29
28
  module Shikashi
30
29
 
@@ -71,6 +70,13 @@ module Shikashi
71
70
  attr_reader :hook_handler
72
71
 
73
72
  #
73
+ # Same as Sandbox.new.run
74
+ #
75
+
76
+ def self.run(*args)
77
+ Sandbox.new.run(Shikashi.global_binding, *args)
78
+ end
79
+ #
74
80
  # Generate a random source file name for the sandbox, used internally
75
81
  #
76
82
 
@@ -113,7 +119,7 @@ module Shikashi
113
119
 
114
120
  privileges = sandbox.privileges[source]
115
121
  if privileges
116
- unless privileges.global_allowed? global_id
122
+ unless privileges.global_write_allowed? global_id
117
123
  raise SecurityError.new("Cannot assign global variable #{global_id}")
118
124
  end
119
125
  end
@@ -121,13 +127,45 @@ module Shikashi
121
127
  nil
122
128
  end
123
129
 
130
+ def handle_gvar(global_id)
131
+ source = get_caller
132
+ privileges = sandbox.privileges[source]
133
+ if privileges
134
+ unless privileges.global_read_allowed? global_id
135
+ raise SecurityError, "cannot access global variable #{global_id}"
136
+ end
137
+ end
138
+
139
+ nil
140
+ end
141
+
142
+ def handle_const(name)
143
+ source = get_caller
144
+ privileges = sandbox.privileges[source]
145
+ if privileges
146
+ unless sandbox.base_namespace.constants.include? name
147
+ unless privileges.const_read_allowed? name.to_s
148
+ raise SecurityError, "cannot access constant #{name}"
149
+ end
150
+ end
151
+ end
152
+
153
+ const_value(sandbox.base_namespace.const_get(name))
154
+ end
155
+
124
156
  def handle_cdecl(klass, const_id, value)
125
157
  source = get_caller
126
158
 
127
159
  privileges = sandbox.privileges[source]
128
160
  if privileges
129
- unless privileges.const_allowed? "#{klass}::#{const_id}"
130
- raise SecurityError.new("Cannot assign const #{klass}::#{const_id}")
161
+ unless privileges.const_write_allowed? "#{klass}::#{const_id}"
162
+ if (klass == Object)
163
+ unless privileges.const_write_allowed? const_id.to_s
164
+ raise SecurityError.new("Cannot assign const #{const_id}")
165
+ end
166
+ else
167
+ raise SecurityError.new("Cannot assign const #{klass}::#{const_id}")
168
+ end
131
169
  end
132
170
  end
133
171
 
@@ -255,19 +293,18 @@ module Shikashi
255
293
  #
256
294
  #
257
295
  def run(*args)
258
- end
259
-
260
- define_eval_method :run
261
- def internal_eval(b_, args)
262
-
263
296
  newargs = Array.new
264
297
 
265
298
  timeout = args.pick(:timeout) do nil end
266
299
  privileges_ = args.pick(Privileges,:privileges) do Privileges.new end
267
300
  code = args.pick(String,:code)
268
- binding_ = args.pick(Binding,:binding) do b_ end
301
+
269
302
  source = args.pick(:source) do nil end
270
303
  base_namespace = args.pick(:base_namespace) do create_adhoc_base_namespace end
304
+
305
+ binding_ = args.pick(Binding,:binding) do
306
+ nil
307
+ end
271
308
  @base_namespace = base_namespace
272
309
  no_base_namespace = args.pick(:no_base_namespace) do false end
273
310
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shikashi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 1
10
- version: 0.3.1
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Dario Seminara
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-22 00:00:00 -03:00
18
+ date: 2011-04-28 00:00:00 -03:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -26,12 +26,12 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- hash: 23
29
+ hash: 15
30
30
  segments:
31
31
  - 0
32
- - 2
32
+ - 4
33
33
  - 0
34
- version: 0.2.0
34
+ version: 0.4.0
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
37
  - !ruby/object:Gem::Dependency
@@ -50,22 +50,6 @@ dependencies:
50
50
  version: 0.1.0
51
51
  type: :runtime
52
52
  version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: evalmimic
55
- prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- hash: 27
62
- segments:
63
- - 0
64
- - 1
65
- - 0
66
- version: 0.1.0
67
- type: :runtime
68
- version_requirements: *id003
69
53
  description:
70
54
  email: robertodarioseminara@gmail.com
71
55
  executables: []