Michael Neumann wrote:

> gabriele renzi wrote:
>> I'm not sure, but maybe you simply want a thread running at $SAFE>4
>> and another one accessing the clean data?
> Not that I need this feature, but I'd like it :-)

Here's an implementation:

   # 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 = nil

     begin
       thread = Thread.new do
         $-w = nil

         sandbox ||= Object.new.taint

         yield(sandbox) if block_given?

         $SAFE = 5
         eval(code, sandbox.send(:binding))
       end
       value = thread.value
       result = Marshal.load(Marshal.dump(thread.value))
     rescue Exception => error
       error = Marshal.load(Marshal.dump(error))
     end

     return result, error
   end

However in current Ruby versions there is a way to escape the sandbox 
via ObjectSpace#define_finalizer. I suppose that this could be worked 
around by overloading it with a version that gets the $SAFE level of the 
caller via Binding.of_caller and then applies it to the passed-in 
handler via  eval "$SAFE = #{caller_safe}", block.

But I'm not sure whether that solution would be 100% secure and I'd like 
to avoid adding a dependency to Binding.of_caller here.

Matz is aware of that problem (ts has discovered and reported it) and as 
far as I know it will be fixed in Ruby 1.8.2.

> Regards,
>   Michael

More regards,
Florian Gross