From: Florian Gross Date: 2004-07-21T20:37:06+09:00 Subject: Re: Safe Ruby Environment 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