This issue has been discussed at security / ruby-lang.org, but matz told
me it being appropiate to bring this into an open discussion, so I'm
writing this.
When you make a sandbox (for instance, you may want to execute a
user-generated unreliable code), some implementations can be taken. The
easiest way is to make a thread and let the safe level rise.
require 'timeout'
def sandbox(t) # :yields:
timeout(t) {
Thread.new {
$SAFE = 4
yield
}.join.value
}
rescue Exception
puts $!
abort
end
but this thread-and-safe-level menu is futile for some kind of DoS
attack, as I found this code:
sandbox(1) {
(l = lambda { Thread.new { l.call } while true }).call
}
can never exit with TimeoutError on some machine (at least mine).
My report for security / ruby-lang.org was that even you use forkedtimeout
(http://raa.ruby-lang.org/project/forkedtimeout/), there is a way to
escape from that child process and an evil process can live much longer
than we expected (even in $SAFE=4). I believe that bug will soon be
fixed so I won't tell any details, but the point is that $SAFE
protection is not sufficient to save us form some kind of attacks.
So the question is: how should we construct a sandbox that protect us
from evil codes? Or is it possible? Otherwise, what feature should be
added to (or removed form) the ruby? Once the bug I reported was fixed,
I think the safest way is that you use forkedtimeout along with
Process.setrlimit to restrict the consumption of resource, then raise
the safe level. Is this OK or have some trouble?
Thanks.