ts wrote:

>>>>>>"F" == Florian Gross <flgr / ccan.de> writes:
> F>          $SAFE = 5
> F>          eval(code, sandbox.send(:binding))
> F>        end
> F>        value = thread.value
> F>        result = Marshal.load(Marshal.dump(thread.value))
>  it always an error to evaluate the result with a different value of $SAFE 

Hm, right. It was an old version, sorry for that. This one should work 
correctly: (Except the ObjectSpace#define_finalizer problem)

>   # Runs passed code in a relatively safe sandboxed environment.
>   # 
>   # You can pass a block which is called with the sandbox as its first 
>   # argument to apply custom changes to the sandbox environment.
>   # 
>   # Returns an Array with the result of the executed code and
>   # an exception, if one occurred.
>   # 
>   # Example of usage:
>   # 
>   #   result, error = safe "1.0 / rand(10)"
>   #   puts if error then
>   #     "Error: #{error.inspect}"
>   #   else
>   #     result.inspect
>   #   end
>   def safe(code, sandbox = nil)
>     error, result = nil, nil
> 
>     begin
>       thread = Thread.new do
>         sandbox ||= Object.new.taint
>         yield(sandbox) if block_given?
> 
>         $-w = nil
>         $SAFE = 5
> 
>         eval(code, sandbox.send(:binding))
>       end
>       result = secure_object(thread.value)
>     rescue Exception => error
>       error = secure_object(error)
>     end
> 
>     return result, error
>   end
> 
>   def secure_object(obj)
>     # We can't dup immediate values. But that's no problem
>     # because most of them can't have any singleton methods
>     # anyway. (nil, true and false can, but they can't be
>     # defined in safe contexts.)
>     immediate_classes = [Fixnum, Symbol, NilClass, TrueClass, FalseClass]
>     return obj if immediate_classes.any? { |klass| klass === obj }
> 
>     # Dup won't copy any singleton methods and without any
>     # of them the Object will be safe. (But we can't call
>     # the Object's .dup because it might be evil already.)
>     safe_dup = Object.instance_method(:dup).bind(obj)
>     safe_dup.call
>   end

I believe this one to be safe, but I'd prefer to be proven the opposite 
by you instead of some malicious attacker.

Regards,
Florian Gross