Sorry it took so long, but I only find time in the evenings to work on this. Clemens Hintze <c.hintze / gmx.net> wrote in > > sandbox.execute("p %x(ls -l /)") > sandbox.execute("exec 'ls -l /'") > sandbox.execute("Thread.new { sleep 60000 } while 1") > sandbox.execute("def endless; t = Object.clone; endless end; endless") > AND "NAKAMURA, Hiroshi" <nahi / keynauts.com> wrote in <JIEJKAMAONAMHNNAOOOLGEONCEAA.nahi / keynauts.com>: >Though I did not follow this thread(sorry), why don't >you use $SAFE, ThreadGroup and Thread#priority? > >1. Create new aThreadGroup >2. Create new aThread for sandbox >3. Set appropriate $SAFE level to aThread >4. Set low priority to aThread >5. Add aThread to aThreadGroup >6. Eval code in aThread >7. Kill threads in aThreadGroup.list when timeout > All true (of course). The following solution handles all the /cle vulnerabilities and checks for overly Thread- and Object-creation. Also the execution time is checked. Here we go: --> BEGIN class Thread def Thread.inherited(sub) raise (SecurityError, "You may not subclass Thread") end end class SandboxExecutionContext def system(cmd) raise (SecurityError, "You may not use system") end def exec(*cmd) raise (SecurityError, "You may not use 'exec'") end def require(modName) raise (SecurityError, "You may not use 'require'") end def playground return binding end def `(cmd) # ` raise (SecurityError, "You may not issue ``-commands") end class File def File.open(*args) raise (SecurityError, "You may not open a File") end end end class Sandbox def initialize(level = 2, maxRunTime = 15, maxThreadCount = 10, maxNewObjects = 10000) @level = level @maxRunTime = maxRunTime @maxThreadCount = maxThreadCount @maxNewObjects = maxNewObjects @sandboxThreadGroup = ThreadGroup.new Thread.abort_on_exception= true @context = SandboxExecutionContext.new.playground end def threadCount return ObjectSpace.each_object (Thread) {} end def startWatchDogThread @watchdogThread = Thread.new { ObjectSpace.garbage_collect objectsBeforeLaunch = ObjectSpace.each_object {} runningForSecs = 0 begin while true do if (runningForSecs > @maxRunTime) then raise (SecurityError, "Your script may only run for #{@maxRunTime}sec") end ObjectSpace.garbage_collect if ((ObjectSpace.each_object {} - objectsBeforeLaunch) > @maxNewObjects) then raise (SecurityError, "You may only create #{@maxNewObjects} objects") end if (threadCount() > @maxThreadCount) then raise (SecurityError, "You may only use #{@maxThreadCount} Threads") end sleep 1 runningForSecs += 1 end # while rescue SecurityError => detail myMatch = /.*:.*:.*':(.*)/.match(detail) # ' if not(myMatch.nil?) then print "\nThere has been a security violation: " + myMatch[1] + "\n" else print "\nThere has been a security violation: " + detail + "\n" end @sandboxThreadGroup.list.each { | th | th.kill } end } # end_of_thread end def execute(exeCmd) exeCmd.untaint startWatchDogThread() @sandboxThread = Thread.new { $SAFE = @level begin eval(exeCmd, @context) rescue SecurityError => detail myMatch = /.*:.*:.*':(.*)/.match(detail) # ' if not(myMatch.nil?) then print "\nThere has been a security violation: " + myMatch[1] + "\n" else print "\nThere has been a security violation: " + detail + "\n" end rescue Exception => detail myMatch = /.*:(.*):.*':(.*)/.match(detail) # ' if not(myMatch.nil?) then lineNr = myMatch[1] errorTxt = myMatch[2].gsub(/Sandbox::/,'') print "\nError on line " + lineNr + ":" + errorTxt + "\n" else print "\nError :" + detail + "\n" end end } @sandboxThread.priority= -5 # very low @sandboxThreadGroup.add(@sandboxThread) @sandboxThread.join() # wait for completion sleep .1 # give watchThread a chance to terminate neatly if (@watchdogThread.alive?) then @watchdogThread.kill end end end ---> END There is some "noise" in the code because I try to provide exact error output. matz / zetabits.com (Yukihiro Matsumoto) wrote in <978962552.785938.1519.nullmailer / ev.netlab.zetabits.com>: > >The level 3 of $SAFE is just designed for your purpose. If hole >remains, it's my fault, not yours. ;-) > I prefer 2, in order to also give users the eval-command! Now, I am pretty sure this is still not THE solution ;-) Please give me some more HACKS on this Sandbox! I will build-up a RubyUnit testsuite to check all the HACKS/vulnerabilities. Clemens