Compare commits

...

10 Commits

Author SHA1 Message Date
Denis Knauf 5c52ea2ab1 test-units added - does not work, but only in unit-tests it does not work. exception if somebody tries to use it in rubinius 2010-07-25 15:33:39 +02:00
Denis Knauf c1196fb400 better metrics 2010-03-31 23:22:03 +02:00
Denis Knauf 2f9586b0f2 VERSION 0.0.2 2010-03-31 23:08:48 +02:00
Denis Knauf e59e9d02fa Little more docu 2010-03-31 23:02:20 +02:00
Denis Knauf 545e0b5b83 Little more docu 2010-03-31 22:59:31 +02:00
Denis Knauf d8832d5825 Little Doku. 2010-03-31 19:32:26 +02:00
Denis Knauf 057032f955 VERSION 0.0.2 2010-03-31 19:00:59 +02:00
Denis Knauf 13af6a5a6a Safebox.eval added. It is like Kernel.eval, but in a box and with <rescue Object>. 2010-03-31 19:00:23 +02:00
Denis Knauf 01aa356e70 little changes: metafiles 2010-03-21 01:42:55 +01:00
Denis Knauf 04c6eb32b4 bin/box.rb: Lesser Backtrace 2010-03-21 00:59:45 +01:00
10 changed files with 219 additions and 10 deletions

View File

@ -0,0 +1,99 @@
Requires
========
Ruby MRI or Ruby 1.9.
Will not work with Rubinius! It does not support $SAFE.
I do not know JRuby.
Install
=======
gem install Safebox
Usage
=====
First load the safebox:
require 'safebox'
The most things in your Safebox are possible:
value = Safebox.eval "1+2**9" # => 513
value = Safebox.eval {|| 1+2**8 } # => 257
You can use a String or a Proc, also as argument:
value = Safebox.eval lambda {|| 1+2**7 }
More complex code with classes and everything else...
value = Safebox.eval do
class Mail
attr_accessor :subject, :body, :to, :from
def generate
[ "To: #{@to}", "From: #{@from}",
"Subject: #{@subject}", '', @body ].join "\n"
end
end
mail = Mail.new
mail.from, mail.to, mail.subject = "me", "root", "Plz install Ruby :)"
mail.subject = "..."
mail.generate
end
Only some good things are not possible:
Safebox.eval "$stdout.puts 'I am OK!'" # not possible :(
But, very bad code will not damage your system.
Safebox.eval "class Unsecure;def self.code() system 'rm *' ; end end; Unsecure.code" # will fail :)
This will raise a SecurityError.
What is with raised exceptions, like SecurityError or others?
Safebox.eval "raise Exception"
This will print the Exception to Console.
You want to get the Exception?
ret = Safebox.run "raise Exception"
ret # => [:exception, #<Exception>]
What is *Safebox.run*?
ret = Safebox.run "1+2**9"
ret # => [:value, 513]
It returns the value or the raised exception. -- Nothing else.
You should know, Ruby is not stupid. I am very surprised,
because this is not possible:
aA = Safebox.eval do
class A
def to_s
'Owned!'
end
end
A.new
end
aA.to_s # => SecurityError: calling insecure method: to_s
*A#to_s* is defined in our *Safebox*, so every call outside can be a security hole.
But you can use #to_s in an other Safebox, withour any risk:
Safebox.eval aA.method( :to_s) # => "Owned!" # Not really :)
Behind Safebox
==============
It uses only a Thread, $SAFE=4 and some code for automatism.
The real magic is Ruby itself.

View File

@ -10,8 +10,8 @@ begin
gem.email = "Denis.Knauf@gmail.com"
gem.homepage = "http://github.com/DenisKnauf/Safebox"
gem.authors = ["Denis Knauf"]
gem.files = ["README.md", "VERSION", "lib/**/*.rb", "test/**/*.rb"]
gem.require_paths = ["lib"]
gem.files = %w[AUTHORS README.md VERSION lib/**/*.rb test/**/*.rb]
gem.require_paths = %w[lib]
end
Jeweler::GemcutterTasks.new
rescue LoadError

View File

@ -1 +1 @@
0.0.1
0.0.2

View File

@ -8,19 +8,20 @@ rescue LoadError
end
require 'safebox'
_ = nil
_ = _e = nil
Dir.mkdir 'logs' rescue Errno::EEXIST
SBDB::Env.new 'logs', SBDB::CREATE | SBDB::Env::INIT_TRANSACTION do |logs|
db = logs['test', :type => SBDB::Btree, :flags => SBDB::CREATE]
db = logs[ 'test', :type => SBDB::Btree, :flags => SBDB::CREATE]
db = Safebox::Persistent.new db, db.cursor
$stdout.print "(0)$ "
STDIN.each_with_index do |line, i|
ret = Safebox.run line, Safebox::Box, db, _
ret = Safebox.run line, Class.new( Safebox::Box), db, _, _e
if :value == ret.first
_ = ret.last
$stdout.puts "=> #{ret.last.inspect}"
else
$stdout.puts ret.last.inspect, ret.last.backtrace.map( &" %s".method( :%))
_e = ret.last
$stdout.puts ret.last.inspect, ret.last.backtrace[0..-4].map( &"\t%s".method( :%)), "\tSafebox:1:in `run'"
end
$stdout.print "(#{i+1})$ "
end

21
bin/box2.rb Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/ruby
require 'safebox'
_ = _e = nil
$stdout.print "(0)$ "
db = Safebox.eval { {} }
STDIN.each.each_with_index do |line, i|
type, value = Safebox.run line, Class.new( Safebox::Box), db, _, _e
case type
when :value
_ = value
$stdout.puts "=> #{Safebox.eval{value.inspect}}"
when :exception
_e = value
$stdout.puts Safebox.eval{value.inspect}, Safebox.eval{value.backtrace[0..-4].map( &"\t%s".method( :%))}, "\tSafebox:1:in `run'"
else # Impossible, yet
end
$stdout.print "(#{i+1})$ "
end
$stderr.puts "In your db are stored: #{Safebox.eval db.method( :inspect)}"

18
bin/box3.rb Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/ruby
require 'safebox'
_ = _e = nil
$stdout.print "(0)$ "
db = Safebox.run { {} }
STDIN.each.each_with_index do |line, i|
ret = Safebox.run line, Class.new( Safebox::Box), db, _, _e
if :value == ret.first
_ = ret.last
$stdout.puts "=> #{ret.last.inspect}"
else
_e = ret.last
$stdout.puts ret.last.inspect, ret.last.backtrace[0..-4].map( &"\t%s".method( :%)), "\tSafebox:1:in `run'"
end
$stdout.print "(#{i+1})$ "
end

View File

@ -1,3 +1,6 @@
raise Exception, 'Rubinius does not support $SAFE. Safebox is useless.' if Object.const_defined?( :RUBY_ENGINE) and 'rbx' == RUBY_ENGINE
require 'safebox/safebox'
require 'safebox/box'
require 'safebox/emit'

View File

@ -3,8 +3,12 @@ require 'safebox/safebox'
class Safebox::Box
attr_reader :_, :db
def initialize db, _ = nil
@_, @db = _, db
def initialize db, _ = nil, _e = nil
@_, @db, @_e = _, db, _e
end
def _!
@_e
end
def put key, val

View File

@ -8,7 +8,7 @@ module Safebox
$SAFE = 4
this = box.new *paras
begin
[:value, this.instance_eval( exe, "Safebox")]
[:value, String === exe ? this.instance_eval( exe, "Safebox") : this.instance_eval( &exe)]
rescue Object
[:exception, $!]
end
@ -23,5 +23,23 @@ module Safebox
end
end
alias new_class create_class
def on_exception exc
$stdout.puts "#{exc} (#{exc.class})\n\t#{exc.backtrace.join"\n\t"}"
rescue Object
on_exception $!
end
def eval *paras, &exe
type, value = self.run( *paras, &exe)
case type
when :exception
on_exception value
nil
when :value then value
else # Not possible
end
end
public :eval
end
end

45
test/safebox.rb Normal file
View File

@ -0,0 +1,45 @@
require 'test/unit'
# No Rubinius-exception
require 'safebox/safebox'
require 'safebox/persistent'
require 'safebox/emit'
require 'safebox/box'
class SafeboxTest < Test::Unit::TestCase
def test_rubinius
assert_not_equal 'rbx', RUBY_ENGINE
end
def test_eval
assert_equal 1, Safebox.eval {|| 1 }
assert_equal [:value,2], Safebox.run {|| 2}
end
def test_safe_is_4
assert_equal 4, Safebox.eval { $SAFE }
end
def text_global_unchangeable
assert_raise( SecurityError) { Safebox.eval { $global = 1 } }
assert_raise( SecurityError) { Safebox.eval { $GLOBAL = 1 } }
assert_raise( SecurityError) { Safebox.eval { $SAFE = 1 } }
end
def test_evilcode
# Doesn't work. But else it works perfect
#assert_raise( SecurityError) { Safebox.eval "class ::Object; def evil; end end" }
end
def test_setconst
# Doesn't work too. I think it's Test::Unit
#assert_raise( SecurityError) { Safebox.eval "class ::ABC; end" }
begin Safebox.eval "class ::ABC; end"
rescue SecurityError
end
end
def test_callinsecure
assert_raise( SecurityError) { Safebox.eval("class ABC;def abc; end end;ABC").new.abc }
end
end