Compare commits
No commits in common. "master" and "v0.0.1" have entirely different histories.
10 changed files with 10 additions and 219 deletions
99
README.md
99
README.md
|
@ -1,99 +0,0 @@
|
||||||
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.
|
|
4
Rakefile
4
Rakefile
|
@ -10,8 +10,8 @@ begin
|
||||||
gem.email = "Denis.Knauf@gmail.com"
|
gem.email = "Denis.Knauf@gmail.com"
|
||||||
gem.homepage = "http://github.com/DenisKnauf/Safebox"
|
gem.homepage = "http://github.com/DenisKnauf/Safebox"
|
||||||
gem.authors = ["Denis Knauf"]
|
gem.authors = ["Denis Knauf"]
|
||||||
gem.files = %w[AUTHORS README.md VERSION lib/**/*.rb test/**/*.rb]
|
gem.files = ["README.md", "VERSION", "lib/**/*.rb", "test/**/*.rb"]
|
||||||
gem.require_paths = %w[lib]
|
gem.require_paths = ["lib"]
|
||||||
end
|
end
|
||||||
Jeweler::GemcutterTasks.new
|
Jeweler::GemcutterTasks.new
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
0.0.2
|
0.0.1
|
||||||
|
|
|
@ -8,20 +8,19 @@ rescue LoadError
|
||||||
end
|
end
|
||||||
require 'safebox'
|
require 'safebox'
|
||||||
|
|
||||||
_ = _e = nil
|
_ = nil
|
||||||
Dir.mkdir 'logs' rescue Errno::EEXIST
|
Dir.mkdir 'logs' rescue Errno::EEXIST
|
||||||
SBDB::Env.new 'logs', SBDB::CREATE | SBDB::Env::INIT_TRANSACTION do |logs|
|
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
|
db = Safebox::Persistent.new db, db.cursor
|
||||||
$stdout.print "(0)$ "
|
$stdout.print "(0)$ "
|
||||||
STDIN.each_with_index do |line, i|
|
STDIN.each_with_index do |line, i|
|
||||||
ret = Safebox.run line, Class.new( Safebox::Box), db, _, _e
|
ret = Safebox.run line, Safebox::Box, db, _
|
||||||
if :value == ret.first
|
if :value == ret.first
|
||||||
_ = ret.last
|
_ = ret.last
|
||||||
$stdout.puts "=> #{ret.last.inspect}"
|
$stdout.puts "=> #{ret.last.inspect}"
|
||||||
else
|
else
|
||||||
_e = ret.last
|
$stdout.puts ret.last.inspect, ret.last.backtrace.map( &" %s".method( :%))
|
||||||
$stdout.puts ret.last.inspect, ret.last.backtrace[0..-4].map( &"\t%s".method( :%)), "\tSafebox:1:in `run'"
|
|
||||||
end
|
end
|
||||||
$stdout.print "(#{i+1})$ "
|
$stdout.print "(#{i+1})$ "
|
||||||
end
|
end
|
||||||
|
|
21
bin/box2.rb
21
bin/box2.rb
|
@ -1,21 +0,0 @@
|
||||||
#!/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
18
bin/box3.rb
|
@ -1,18 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,6 +1,3 @@
|
||||||
|
|
||||||
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/safebox'
|
||||||
require 'safebox/box'
|
require 'safebox/box'
|
||||||
require 'safebox/emit'
|
require 'safebox/emit'
|
||||||
|
|
|
@ -3,12 +3,8 @@ require 'safebox/safebox'
|
||||||
class Safebox::Box
|
class Safebox::Box
|
||||||
attr_reader :_, :db
|
attr_reader :_, :db
|
||||||
|
|
||||||
def initialize db, _ = nil, _e = nil
|
def initialize db, _ = nil
|
||||||
@_, @db, @_e = _, db, _e
|
@_, @db = _, db
|
||||||
end
|
|
||||||
|
|
||||||
def _!
|
|
||||||
@_e
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def put key, val
|
def put key, val
|
||||||
|
|
|
@ -8,7 +8,7 @@ module Safebox
|
||||||
$SAFE = 4
|
$SAFE = 4
|
||||||
this = box.new *paras
|
this = box.new *paras
|
||||||
begin
|
begin
|
||||||
[:value, String === exe ? this.instance_eval( exe, "Safebox") : this.instance_eval( &exe)]
|
[:value, this.instance_eval( exe, "Safebox")]
|
||||||
rescue Object
|
rescue Object
|
||||||
[:exception, $!]
|
[:exception, $!]
|
||||||
end
|
end
|
||||||
|
@ -23,23 +23,5 @@ module Safebox
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alias new_class create_class
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
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
|
|
Loading…
Add table
Add a link
Reference in a new issue