J
Jonathan Nielsen
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
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