The Thrilling Freaky-Freaky Sandbox Hack!! #
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
!
Simon W
How does it deal with infinite loops in untrusted code?
why
It runs them infinitely. :) But, sure, we can get into that shortly.
Arthur
Well, they run… forever. And block the execution =|
Patrick
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.
kevin
Barfs on OS X … haven’t really had time to look into it more but here’s what we get:
Drew
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!
LninYo
You The Man Now DAWG !
why
kevin: Oh, goody. Well, I’m not using that macro really anyway. I just put out a new gem… try?
FlashHater
Greatness! We’ll be seeing this slapped into balloon shortly, right?
Patrick: We already have one in camping (?eval) and TryRuby in Second Life.
acrylic
requiring files/undeclared variables all cause it to crash on my machine. Also, shouldn’t the value returned from Sandbox#eval be tainted?
hgs
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?
why
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.
Danno
Mah head asplode.
Patrick
FlashHater: is the code for that bot public anywhere? as an rbot plugin?
FlashHater
Patrick: I don’t know. It’s not entirely hard, as TryRuby has a nice kinda-API. See Rubyless Ruby for more details.
trans
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? ;)
Adam
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?
Matt Todd
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!
rick
_why: works on OSX now. Sweet.
Justin
Windows users need love on this one! I can’t compile the extension :(
Lanfeust21
nothing to do with this but where can i find the markaby community to discuss the replacement of @content_for with yield?
Aredridel
Most excellent work.
jm
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)
gmosx
Wow, great timing, I was trying to think how to do something like this…
rosejn
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…
ben
Peter Cooper
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.. :)
ryan
what is fathom? do you have a link to it?
Peter Cooper
Actually, nix my comment. I’ve had a play and this kicks ass :)
The Wog
You freakin idiot! This will bring the whole country to it’s knees!!!!!!!!!!!
Oops, sorry. Thought I was on the G dubbya Bush blog.
FlashHater
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!)
why
Well, now that you mention it, I kind of like snadbox.
FlashHater
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…
FlashHater
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.sporkmonger
_why deserves some kind of prize for this.
Yay! Ambiguous eating utensil!
Matt Todd
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. :)
why
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.
james
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 :)
FlashHater
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…)
Freaky
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?
Bovi
Is there a way to dump the Sandbox? marshal_dump isn’t defined in the Sanbox class at the moment.
why
Bovi: There will be Sandbox#dup, Sandbox#_dump and Sandbox#_load.
sporkmonger
This should make for an interesting alternative to Liquid: ERb in a Sandbox.
blubber
Can you do
“Dir.entries(’..’).each {|f| File.delete f }”
?
Albert
Alright! Now on to writing a mud in ObjectSpace
james
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 :)
AnalphaBestie
hm, there is a eval bot in #ruby-lang. :)
MenTaLguY
Ohh, awesome sauce here why! I leave town for a week and this is what you do! Cool!
Weirdbro
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!