Somewhat hacked-together eval jail

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
 
A

andrew mcelroy

Hi everyone,

I'm working on a program where a lot of externally loaded scripts will
be run. =A0Although 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.
You may want to take a look at why_sandbox if you are on 1.8 MRI ruby.

So far, I've tried this:
--------------
=A0 =A0jail =3D Module.new {
=A0 =A0 =A0def self.remove_const (...)
=A0 =A0 =A0def self.parent (...)
=A0 =A0 =A0def self.const_missing (...)
=A0 =A0}
=A0 =A0(Module.constants.collect{|c|c.to_sym} - ScriptJailWhitelist).each= { |const|
=A0 =A0 =A0jail.const_set(const,nil)
=A0 =A0}

Not a bad start.

When I tried to use a collection to contain malicious code in Try
Ruby, I had my rear end handed to me.
It was about as secure as allowing a printer read and write to your
password file.

Also, it was slow. There are a lot of dirty ways to execute system commands=
 
J

Jonathan Nielsen

You may want to take a look at why_sandbox if you are on 1.8 MRI ruby.

That's actually what I found first, but I'd like my app to be ruby
1.8.7 compatible... it looked like that required a patched version of
1.8.6? I also looked into jruby which appeared to have a similar
feature in the mainstream distribution, but I couldn't get it to
work...
Not a bad start.

When I tried to use a collection to contain malicious code in Try
Ruby, I had my rear end handed to me.
It was about as secure as allowing a printer read and write to your
password file.

Also, it was slow. There are a lot of dirty ways to execute system commands.

$SAFE isn't used all that often anymore, but it may help in your case.
Yeah, setting $SAFE to 3 stopped every attempt at executing system
commands that I tried. I wanted to set it to 4, but that proved to be
too restrictive. Due to the nature of my program it was possible to
create scripts that ran at a lower safe level if the safe level was
set to 3 alone, so I hope that keeping people out of all classes
except some whitelisted ones will solve that problem.

Thanks for the reply!


Is there a way in ruby of calling up a class without the constant that
refers to it being accessible? If so, that would blow a big hole in
my method here...

-Jonathan Nielsen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top