next up previous contents index
Search Next: eRuby und mod_ruby Up: Sicherheit (nicht nur) fürs Previous: Sicherheitsstufen   Contents   Index


Eine Sandbox für Ruby-Programme

Wir betrachten [*]eine Sandbox-Implementation für Ruby, die auf

Clemens' RubyCHannel (http://www.ruby.ch) eingesetzt wird. Sie ermöglicht es, (fast) beliebigen Ruby-Code im Webbrowser einzugeben und auf dem Server des RubyChannel ausführen zu lassen.

Damit der Server mögliche "`Attacken"' übersteht, müssen bestimmte Funktionen und Programmiertechniken speziell kontrolliert werden. Schließlich ist der Online-Interpreter auf ruby.ch ja ausdrücklich zum Probieren gedacht, und wer wollte nicht schon immer mal sehen, was bei folgenden Eingaben passiert:

system("rm -rf /")  # ;-(

# oder auch:
liste = []
while true do
  liste.push(String.new("test")  
end

Um diese "`gefährlichen"' Skripte zu unterbinden, gleichzeitig aber möglichst große Freiheiten zu gewähren, wird die folgende Sandbox "`dazwischengeschaltet"'. Der Auszug zeigt die sicherheitsrelevanten Teile der Sandbox auf. Der gesamte Code befindet sich im Anhang F. Die mit * markierten Zeilen sind aus drucktechnischen Gründen umgebrochen worden, # kennzeichnet Erläuterungen.

  1 class Sandbox
.................
 23   def starteWaechterThread
 24     @waechterThread = Thread.new {
 25     ObjectSpace.garbage_collect # Aufräumen!
 26     anzObjekteAmAnfang = ObjectSpace.each_object {}
 27     laeuftSeit = 0
 28     begin
 29       while not(@done) do

  #         Skripte haben eine begrenzte Laufzeit ...
 30         if (laeuftSeit > @maxLaufzeit) then
 31           raiseSecurityError("Die Zeit ist 
  *             abgelaufen (#{@maxRunTime}sec)")
 32         end
 33         ObjectSpace.garbage_collect

  #         ... dürfen nicht zu viele Objekte kreieren
 34         if ((ObjectSpace.each_object {} - 
  *           anzObjekteAmAnfang) > @maxNeueObjekte) 
  *           then
 35           raiseSecurityError("Es wurden schon mehr
  *             als #{@maxNewObjects} Objekte erzeugt!")
 36         end

  #         ... oder zu viele Threads erzeugen
 37         if (threadCount > @maxThreadCount) then
 38           raiseSecurityError("Es dürfen maximal
  *             #{@maxThreadCount} Threads erzeugt
  *             werden!")
 39         end
 40         sleep 1
 41         laeuftSeit += 1
 42       end # while
.................
 54   def starteInDerSandbox(exeCmd)
 55       begin
 56         eval(exeCmd, Object.module_eval("binding")) 
 57       rescue SecurityError => detail
.................

  #   cmd ist das auszuführende Skript
 65   def fuehreAus(cmd)
.................

  #     vor der Ausführung $SAFE hochsetzen
 68     cmd = "$SAFE = #{@level}\n" + cmd

  #     hochpriorisierter Monitor
 69     starteWaechterThread # Unser BIG BROTHER ;-)

  #     sehr niedrig priorisierter Thread für das Skript
 70     @sandboxThreadGroup.add(@sandboxThread =
  *       Thread.new {
 71         starteInDerSandbox(exeCmd)
 72       })
 73     @sandboxThread.priority= -5   # sehr niedrig!
.................
 77   end # fuehreAus
 78 end # class Sandbox

Das Prinzip: Der auszuführende Code wird in einem (einer) niedrigpriorisierten [#73] Thread(-Gruppe) [#70-#72] per eval [#56] ausgeführt. Daneben läuft in einem hochpriorisierten Thread der "`Wächter"' [#24-#42]. Dieser überwacht unter anderem, dass das Programm terminiert [#30-#32], nicht zu viele neue Objekte erzeugt [#34-#36] und nicht zu viele Threads [#37-#39] anstößt. Was in diesem Codeauszug fehlt, sind all die weiteren Restriktionen, welche von der Sandbox (beziehungsweise dem "`Wächter"') verhindert werden. Diese (Restriktionen) sind hauptsächlich durch das Überladen von "`nicht erlaubten"' Kernel-Funktionen implementiert.



Footnotes

... betrachten[*]
"`Sandkasten"' für Ruby-Programme

next up previous contents index
Search Next: eRuby und mod_ruby Up: Sicherheit (nicht nur) fürs Previous: Sicherheitsstufen   Contents   Index
(C) 2002 by dpunkt.de, Armin Roehrl, Stefan Schmiedl, Clemens Wyss 2002-01-20