From: Jonathan Nielsen Date: 2009-12-29T00:58:00+09:00 Subject: Somewhat hacked-together eval jail Hi everyone, I'm working on a program where a lot of externally loaded scripts will be run. Although the scripts will all be written by trusted (or mostly trusted) sources, I want to implement some form of jail that is at least somewhat difficult to break out of to eval these scripts. So far, I've tried this: -------------- jail = Module.new { def self.remove_const (...) def self.parent (...) def self.const_missing (...) } (Module.constants.collect{|c|c.to_sym} - ScriptJailWhitelist).each { |const| jail.const_set(const,nil) } -------------- which adds local constants to my jail module that 'override' the global ones that would allow someone to break out (for example, TOPLEVEL_BINDING) with the exception of a whitelist that I have defined (Array, Date, Hash, etc) In the initial declaration for the jail Module I also add methods for self.remove_const, self.parent that simply raise an exception. Lastly I add a method for self.const_missing because I have ActiveSupport loaded. I then populate the jail module with methods needed for the script running and do jail.module_eval in a new thread with safe_level 3. (all this work because safe_level 4 was too restrictive for what I needed... heh) As far as possible security problems, perhaps there is a way to get the Object class (some_instance.class) that would allow access to the TOPLEVEL_BINDING constant once again... but I couldn't find a way in my quick experiments. I'm sure there are some holes in this design, but so far I can't find any playing around in irb with a binding inside this Module. I'm hoping someone here might know the language a little better than me and point out anything obvious I might be missing. Again, this doesn't need to be 100% secure, but hey if it is then that's a bonus :) Or if there's a better way to do this that I somehow missed, please enlighten me. Thank you for your time, -Jonathan Nielsen