hoodwink.d enhanced


The Thrilling Freaky-Freaky Sandbox Hack!! #

by why in inspect

Holy cats, I’m proud to offer you this sensational hack today. For me, this is monumental, as it culminates a number of sundry microhacks from the past few years and gets us a step closer to realizing Try Ruby out in the broader kingdoms. This is the sort of thing that will make you want to post spangly angel GIFs in the comments.

Okay, requires a compiler. Then: gem install sandbox --source code.whytheluckystiff.net

Now, to create a sandboxed Ruby interp.

 >> require 'rubygems'
 >> require 'sandbox'

 >> s = Sandbox.new
 => #<Sandbox:0x84dea60>
 >> s.eval("2 + 6")
 => 8
 >> s.eval("'Jimmy'.reverse")
 => "ymmiJ" 
 >> s.eval('"Jimmy".length')
 => 5

Okay, so you can do all the Try Ruby examples. And what about danger?

 >> s.eval("Kernel.fork")
 (eval):1:in `method_missing': uninitialized constant NoMethodError::message (NameError)

Oh, check that out. Not only is Kernel.fork not defined, but NoMethodError isn’t defined either!

And yet, both are defined in the main interpreter outside the sandbox:

 >> Kernel.method(:fork)
 => #<Method: Kernel.fork>
 >> NoMethodError
 => NoMethodError

There are some security holes still being worked out on Ruby-Core, I need a few variables exposed. But, it’s looking really good. Many thanks to MenTaLguY who helped conceive this idea here in the comments.

So what are the implications? Oh, come on!

  • Load multiple Rails apps, Camping apps, Nitro apps into the same interpreter without polluting each other’s namespaces.
  • Allow Ruby code from users of your application without danger of affecting the app itself. (Scriptable wikis, markaby templates, ohhhh so many uses.)
  • Load several different versions of libraries at once (for testing and compatibility issues.)
  • Reloading an app within itself. (Fathom.)
  • Snapshoting an environment for reuse at a later stage. (The sandkit struct stores the whole environment.)

Eval has just become the least evil. alias docile eval!

said on 19 Jul 2006 at 10:16

How does it deal with infinite loops in untrusted code?

said on 19 Jul 2006 at 10:26

It runs them infinitely. :) But, sure, we can get into that shortly.

said on 19 Jul 2006 at 10:29

Well, they run… forever. And block the execution =|

said on 19 Jul 2006 at 10:31

This would make a great tool in a bot on #ruby-lang, so you could:

irb: [1,2,3].each { |n| n + 1 }

and have it show the results on the spot. It would need to have a time limiter and an output limiter, but it would be very handy as a teaching tool.

said on 19 Jul 2006 at 10:32

Barfs on OS X … haven’t really had time to look into it more but here’s what we get:

dyld: NSLinkModule() error
dyld: Symbol not found: _SPECIAL_SINGLETON
  Referenced from: /usr/local/lib/ruby/gems/1.8/gems/sandbox-0.0.11/lib/sand_table.bundle
  Expected in: flat namespace

Trace/BPT trap
said on 19 Jul 2006 at 10:35

Ahhhh, I can see it now. A great ruby colosseum shall come to pass. With ruby scripts battling ruby scripts to the death! And one ruby interpreter to rule them all!

said on 19 Jul 2006 at 10:36

You The Man Now DAWG !

said on 19 Jul 2006 at 10:38

kevin: Oh, goody. Well, I’m not using that macro really anyway. I just put out a new gem… try?

said on 19 Jul 2006 at 10:44

Greatness! We’ll be seeing this slapped into balloon shortly, right?
Patrick: We already have one in camping (?eval) and TryRuby in Second Life.

said on 19 Jul 2006 at 10:59
require "rubygems" 
require "sandbox" 
s = Sandbox.new
$ ruby test.rb 
(eval):1: [BUG] Bus Error
ruby 1.8.4 (2005-12-24) [powerpc-darwin8.6.0]

Abort trap

requiring files/undeclared variables all cause it to crash on my machine. Also, shouldn’t the value returned from Sandbox#eval be tainted?

said on 19 Jul 2006 at 10:59

IIRC , modruby exists so one doesn’t have many interpreters running on the server. If all the cgis run in sandboxes… Or is that silly?

said on 19 Jul 2006 at 11:06

acrylic: It’s because I haven’t finished the exception handling. And, in addition, the return value needs to be Marshalled (and tainted) for import into the master interp.

hgs: Sandboxes are pretty inexpensive. About 16K for the base. The reason mod_ruby doesn’t use multiple interpreters is because it can’t. I’m not suggesting CGIs should each have a sandbox. But each Rails app could have their own.

said on 19 Jul 2006 at 11:09

Mah head asplode.

said on 19 Jul 2006 at 11:13

FlashHater: is the code for that bot public anywhere? as an rbot plugin?

said on 19 Jul 2006 at 11:16

Patrick: I don’t know. It’s not entirely hard, as TryRuby has a nice kinda-API. See Rubyless Ruby for more details.

said on 19 Jul 2006 at 11:19

So you basically took the whole Ruby environment and turned it into a reusable variable. Very cool. Kind of what I suggested in my last ruby-talk post about selector namespaces. Of course Austin bulked and said it would be the doom of Ruby. You’re just using it as a sandbox execution space at this point. Of course that’s all good. But what’s the status on our selector namespace apocalypse? ;)

said on 19 Jul 2006 at 11:34

I am very much in awe. JPG stars and GIF angels for you!

I have been toying with allowing people to write postprocessing scripts for big ugly data queries on a big ugly (well kinda pretty) website I’ve been building. This is exacly what I needed to do it.

Anyone have any tips for getting these fine things to compile on the darkside of win32?

said on 19 Jul 2006 at 11:35

I’m really excited about the prospects of this sandbox. Well done! The examples you give are really, very cool. I’m going to see if I can hack together the little IRC IRB bot. I’ll definitely play with the idea of the reloading app, too. Fun stuff!

Thanks _why and all!

said on 19 Jul 2006 at 12:08

_why: works on OSX now. Sweet.

said on 19 Jul 2006 at 12:53

Windows users need love on this one! I can’t compile the extension :(

said on 19 Jul 2006 at 13:15

nothing to do with this but where can i find the markaby community to discuss the replacement of @content_for with yield?

said on 19 Jul 2006 at 13:31

Most excellent work.

said on 19 Jul 2006 at 13:33

holy freakin hell, I knew you’d come through with this eventually _why. I had faith and was rewarded!

(I’ve wanted this for a rails CMS for some time)

said on 19 Jul 2006 at 13:41

Wow, great timing, I was trying to think how to do something like this…

said on 19 Jul 2006 at 13:54

Sweet! Now textile needs an accomplice API . Meta-textile with scriptability for meta-wiki linkability. The problem is, sand boxes are way 80’s man. These are more like, like pink dumpster gardens…

said on 19 Jul 2006 at 15:07

said on 19 Jul 2006 at 15:35

This is very cool, especially for local use, but you can mimic this functionality using DRb and $SAFE, right? It’s remote and dependent on DRb, of course, but that’s just as safe, right? At least, that’s how ClassRoom works, but I haven’t done much security testing yet.. :)

said on 19 Jul 2006 at 15:38

what is fathom? do you have a link to it?

said on 19 Jul 2006 at 16:06

Actually, nix my comment. I’ve had a play and this kicks ass :)

said on 19 Jul 2006 at 16:30

You freakin idiot! This will bring the whole country to it’s knees!!!!!!!!!!!

Oops, sorry. Thought I was on the G dubbya Bush blog.

said on 19 Jul 2006 at 17:10

I propose a rename, to freakyfreakysandbox. I like the way it rolls off the toung.
Back to the snadbox, I think alot of people have been suggesting this, but _why delivers! (On time, and with minimal damage to the package too!)

said on 19 Jul 2006 at 17:28

Well, now that you mention it, I kind of like snadbox.

said on 19 Jul 2006 at 18:10

I just came back here to check if I had misspelled sandbox, as I am so apt to do. Snadbox is one of those misspellings that would make a good name…

said on 19 Jul 2006 at 19:10
Erk. It seems I have a bug to report. Whil looking through s.methods, I found “require”. Being the inquisitive person I am..
irb(main):005:0> s.require("open-uri") /usr/lib/ruby/1.8/open-uri.rb:280: [BUG] Segmentation fault ruby 1.8.4 (2005-12-24) [i686-linux] And it segfaults. Emo.
said on 19 Jul 2006 at 20:55

_why deserves some kind of prize for this.

Yay! Ambiguous eating utensil!

said on 19 Jul 2006 at 22:44

Fathom is really just a word meaning: to understand. Of course, in this context, it has a bit of ‘hmph!’ to it and it really means “can you imagine how cool this will be?” Fathom. :)

said on 19 Jul 2006 at 23:07

ben: I really appreciate that. I need those holy gals right now.

Okay, some segfaults are starting to disappear and I’ve got some tests that start up hundreds of sandboxes and benchmark. Creating a Sandbox is a bit of a performance hit, so try to reuse them. I mean on my laptop a Ruby process can make about a hundred sandboxes in a second, but can run tenthousand evals in a second.

said on 20 Jul 2006 at 00:33

How does it know what is to be trusted or not? Can someone provide an explanation of why (pardon the pun) I can be sure that this won’t be invalidated down the line by some trivial means of injecting new untrusted code…? How are all the paths of entry being protected? Just curious, as i’ve no idea of the Ruby internals that needed to be tweaked for this hack.

Thanks :)

said on 20 Jul 2006 at 00:49

james: From what I understand, _why’s basicaly shifting the context of the ruby interpreter when you eval in the sandbox. This way, since currently there is no way for a sandbox to see “up”, anything running outside of it is safe. Of course, this is all speculation on my part, as I haven’t the stomach to read C. (well, yes I do, but I have no idea how ruby really works…)

said on 20 Jul 2006 at 04:57

I approve of my name being attached to this as many times as seems appropriate.

Isn’t YARV supposed to support multiple interpreters in a single process?

said on 20 Jul 2006 at 07:50

Is there a way to dump the Sandbox? marshal_dump isn’t defined in the Sanbox class at the moment.

said on 20 Jul 2006 at 08:44

Bovi: There will be Sandbox#dup, Sandbox#_dump and Sandbox#_load.

said on 20 Jul 2006 at 09:07

This should make for an interesting alternative to Liquid: ERb in a Sandbox.

said on 20 Jul 2006 at 09:10

Can you do

“Dir.entries(’..’).each {|f| File.delete f }”


said on 20 Jul 2006 at 10:25

Alright! Now on to writing a mud in ObjectSpace

said on 21 Jul 2006 at 07:59

FlashHater: Right, so the code running the Sandbox can’t be modified by the sandbox itself…

But that still leaves the remaining problem of sandbox code being able to do things it shouldn’t…or is this something you’d just rely on $SAFE fixing?

Anyway, liking the direction this is going, good stuff :)

said on 21 Jul 2006 at 08:26

hm, there is a eval bot in #ruby-lang. :)

said on 21 Jul 2006 at 10:39

Ohh, awesome sauce here why! I leave town for a week and this is what you do! Cool!

said on 06 Aug 2006 at 09:57

Dude, Drew, from way early in the comments, I had already thought of that a while ago, making a Ruby port of the old game droidbattles. But before sandbox, I had no idea how to keep them from just hacking other droids by modifying their classes. Yay for sandbox!

11 Jul 2010 at 21:30

* do fancy stuff in your comment.