From: C Erler Date: 2005-11-23T20:23:29+09:00 Subject: Re: Sandboxing without $SAFE ------=_Part_2203_20475850.1132744966280 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline On 10/11/05, why the lucky stiff wrote: > > I've been playing with Ruby sandboxing alot over the past several > weeks. I've been using remove_const and redefinitions of classes to > limit Ruby rather than $SAFE. I want to offer an interpreter which can > be scripted without needing to learn tainting and still giving the > ability to `eval'. > > Here are the assumptions: > 1. The filesystem is chroot'd or, better yet, a virtual filesystem > implemented in Ruby memory. (Like MockFS.) > 2. Scripts will be monitored for CPU usage and consuming processes will > be killed. > 3. STDERR, STDIN and STDOUT are attached to the user's input and output > (the browser). > 4. The following constants are removed from Object: Continuation, GC, > ObjectSpace, Process. > 5. The following methods are removed or redefined in Kernel: (backtick), > abort, autoload, autoload?, exec, exit, exit!, getc, gets, fork, load, > readline, readlines, require, select, syscall, system, test. > 6. As a part of #1, the following class are redefined to prevent them > from accessing the actual filesystem: File, FileTest, Dir, DBM, > File::Stat. > 7. All communication to the interpreter is done through a UNIXServer > socket, like this: > > s =3D UNIXServer.open( socket_path ) > # .. removal of all constants (including UNIXServer), loading of libs > while true > Thread.start( s.accept ) do |s| > if cmd =3D s.gets > s.write eval(cmd) > s.close > end > end > end > > It's a bit more complicated than this, but you get the idea. > > My questions are three: > 1. Are removed constants and methods available elsewhere in the > interpreter? > 2. Could this be distilled into a general practice, as standard as $SAFE? > 3. In general, what am I overlooking? > > _why > > > Are there any objects of the forbidden classes (or their subclasses or equally-dangerous superclasses) open at all (or maybe redefining the #class method would work) ? For example : puts "Contents of /usr/passwd :\n#{ $stderr.class.for_fd($stderr.class.sysopen('/usr/passwd')).read(2**16) }" IO is just as good as File, so modify it, too. In fact, modifying it might fix File automatically. As seen in that last one, there might be 100 different paths leading to removed things. Maybe make some automated test thing to try its best to trace through everything rooting out every method that returns a reference to, say, GC. Maybe set tripwires on GC to see if they call it, too. Maybe run this on load 'sandbox', if it's somewhat fast. Also, get a list of eac= h Ruby method that is actually written in C and scrutinize each. Ensure that nothing in evil.rb (or anything similar that someone could thin= k up) works. I'm not sure how `rm -rf /` (backticks) work (which method is called), so make sure they don't. If you're running over a network, ensure no outbound packets can be generated. A lot of security software assumes that packets from localhost or the local network are safer. Best of all would be to neuter the Ruby interpreter so that all operating system access functions do nothing and put in we_want_this_to_work__open or something for the cases where you definitely want it to work. It's always safer to use a whitelist than a blacklist. ------=_Part_2203_20475850.1132744966280--