Führen Sie ein nicht vertrauenswürdiges C-Programm in einer Sandbox unter Linux aus, das verhindert, dass Dateien geöffnet, gegabelt usw. werden.

110

Ich habe mich gefragt, ob es eine Möglichkeit gibt, ein nicht vertrauenswürdiges C-Programm unter einer Sandbox unter Linux auszuführen. Etwas, das das Programm daran hindern würde, Dateien oder Netzwerkverbindungen zu öffnen oder Forking, Exec usw.?

Es wäre ein kleines Programm, eine Hausaufgabe, die auf einen Server hochgeladen wird und auf der Unit-Tests ausgeführt werden. Das Programm wäre also nur von kurzer Dauer.

Frank
quelle
Ist dies wie ein einzelnes C-Programm, das Sie 5 Minuten lang einmal ausführen müssen, oder etwas, das Sie ständig ausführen müssen?
Bwawok
Es wäre ein kleines Programm, das hochgeladen wird und auf dem Unit-Tests ausgeführt werden. Das Programm wäre also nur von kurzer Dauer.
Frank
Welche Distribution verwendet das System? Einige Distributionen verfügen über vorgefertigte Tools für das Sandboxing. Ist auf Ihrem System ein Sicherheitsmodell wie SELinux oder AppArmor aktiviert?
Thkala
Ich verwende Fedora 13. Ich untersuche die SELinux Sandbox-Richtlinie. Ich frage mich, welche anderen Optionen es gibt.
Frank
6
Ähnliche Fragen zu Sandboxing / Jailing-Prozessen unter Linux oder Unix: * unix.stackexchange.com/q/6433/4319 * stackoverflow.com/q/3859710/94687 * stackoverflow.com/q/4410447/94687 * stackoverflow.com/q / 1019707/94687
imz - Ivan Zakharyaschev

Antworten:

47

Ich habe Systrace verwendet, um nicht vertrauenswürdige Programme sowohl interaktiv als auch im automatischen Modus zu sandboxen . Es verfügt über ein ptrace()Backend auf Basis, das die Verwendung auf einem Linux-System ohne besondere Berechtigungen ermöglicht, sowie über ein weitaus schnelleres und leistungsfähigeres Backend, das das Patchen des Kernels erfordert.

Es ist auch möglich, eine Sandbox auf Unix-ähnlichen Systemen mit zu erstellen chroot(1), obwohl dies nicht ganz so einfach oder sicher ist. Linux-Container und FreeBSD-Jails sind eine bessere Alternative zu Chroot. Eine andere Alternative unter Linux ist die Verwendung eines Sicherheitsframeworks wie SELinux oder AppArmor , das ich für Produktionssysteme vorschlagen würde.

Wir könnten Ihnen mehr helfen, wenn Sie genau sagen würden, was Sie tun möchten.

BEARBEITEN:

Systrace würde für Ihren Fall funktionieren, aber ich denke, dass etwas, das auf dem Linux-Sicherheitsmodell basiert, wie AppArmor oder SELinux, eine standardisiertere und daher bevorzugte Alternative ist, abhängig von Ihrer Distribution.

EDIT 2:

Während chroot(1)es auf den meisten (allen?) Unix-ähnlichen Systemen verfügbar ist, gibt es einige Probleme:

  • Es kann ausgebrochen werden. Wenn Sie tatsächlich nicht vertrauenswürdige C-Programme auf Ihrem System kompilieren oder ausführen, sind Sie für dieses Problem besonders anfällig. Und wenn Ihre Schüler so etwas wie meine sind, wird jemand versuchen, aus dem Gefängnis auszubrechen.

  • Sie müssen eine vollständige unabhängige Dateisystemhierarchie mit allem erstellen, was für Ihre Aufgabe erforderlich ist. Sie müssen keinen Compiler in der Chroot haben, aber alles, was zum Ausführen der kompilierten Programme erforderlich ist, sollte enthalten sein. Es gibt zwar Dienstprogramme, die dabei helfen, aber es ist immer noch nicht trivial.

  • Sie müssen die Chroot pflegen. Da es unabhängig ist, werden die Chroot-Dateien nicht zusammen mit Ihrer Distribution aktualisiert. Sie müssen entweder die Chroot regelmäßig neu erstellen oder die erforderlichen Update-Tools hinzufügen, was im Wesentlichen erfordern würde, dass es sich um eine vollständige Linux-Distribution handelt. Sie müssen auch die System- und Benutzerdaten (Kennwörter, Eingabedateien usw.) mit dem Hostsystem synchronisieren.

  • chroot()schützt nur das Dateisystem. Es verhindert nicht, dass ein Schadprogramm Netzwerk-Sockets öffnet oder ein schlecht geschriebenes Programm jede verfügbare Ressource aufnimmt.

Das Problem der Ressourcennutzung ist allen Alternativen gemeinsam. Dateisystemkontingente verhindern, dass Programme die Festplatte füllen. Die richtigen Einstellungen ulimit( setrlimit()in C) können vor Überbeanspruchung des Speichers und Gabelbomben schützen und CPU-Schweinen Einhalt gebieten. nice(1)kann die Priorität dieser Programme verringern, sodass der Computer problemlos für alle Aufgaben verwendet werden kann, die als wichtiger erachtet werden.

thkala
quelle
systrace arbeitete für mich für einfache Programme, blieb aber auf unbestimmte Zeit stecken, als GNU als (1) von GCC ausgeführt wurde. Also habe ich es aufgegeben. Es ist ein nicht fixiertes Fehler in systrace: forum.soft32.com/linux/...
pts
Gibt es eine Möglichkeit, um sicherzustellen, dass gemeinsam genutzter Speicher, Nachrichtenwarteschlangen und Semaphoren nicht von Sandbox-Prozessen gemeinsam genutzt werden?
Daveagp
1
Die Systrace-Verbindung ist unterbrochen.
Collin
2
Was ist mit Firejail? Sie müssen die fs nicht mehr damit pflegen.
m3nda
18

Ich habe einen Überblick über Sandbox-Techniken unter Linux geschrieben kürzlich . Ich denke, Ihr einfachster Ansatz wäre die Verwendung von Linux-Containern (lxc), wenn Sie nichts dagegen haben, zu forken und so weiter, was in dieser Umgebung nicht wirklich wichtig ist. Sie können dem Prozess ein schreibgeschütztes Root-Dateisystem, eine isolierte Loopback-Netzwerkverbindung geben und ihn trotzdem problemlos beenden und Speichergrenzen usw. festlegen.

Seccomp wird etwas schwierig, da der Code nicht einmal Speicher zuordnen kann.

Selinux ist die andere Option, aber ich denke, es könnte mehr Arbeit als ein Container sein.

Justin Cormack
quelle
6

Mit Qemu können Sie Aufgaben schnell testen. Dieser Vorgang dauert auf meinem 5 Jahre alten Laptop weniger als 5 Sekunden.

Nehmen wir an, der Schüler muss ein Programm entwickeln, das vorzeichenlose Ints in seiner eigenen Zeile verwendet, bis eine Zeile mit "-1" eintrifft. Das Programm sollte dann alle Ints mitteln und "Average:% f" ausgeben. So können Sie das Programm vollständig isoliert testen:

  1. root.binHolen Sie sich zuerst von Jslinux, wir werden das als Userland verwenden (es hat den tcc C-Compiler):

    wget https://github.com/levskaya/jslinux-deobfuscated/raw/master/root.bin

  2. Wir möchten die Einreichung des Schülers einfügen root.bin, also richten Sie das Loop-Gerät ein:

    sudo losetup /dev/loop0 root.bin

    (Sie könnten auch fuseext2 dafür verwenden, aber es ist nicht sehr stabil. Wenn es sich stabilisiert, benötigen Sie für nichts davon root)

  3. Erstellen Sie ein leeres Verzeichnis:

    mkdir mountpoint

  4. Montieren root.bin:

    sudo mount /dev/loop0 mountpoint

  5. Geben Sie das gemountete Dateisystem ein:

    cd mountpoint.

  6. Rechte reparieren:

    sudo chown -R `whoami` .

  7. mkdir -p etc/init.d
  8. vi etc/init.d::

    #!/bin/sh
    cd /root
    echo READY 2>&1 > /dev/ttyS0
    tcc assignment.c 2>&1 > /dev/ttyS0
    ./a.out 2>&1 > /dev/ttyS0
    
  9. chmod +x etc/init.d/rcS

  10. Kopieren Sie die Übermittlung auf die VM:

    cp ~/student_assignment.c root/assignment.c

  11. Beenden Sie den Root-FS der VM:

    cd ..

  12. sudo umount mountpoint
  13. Jetzt ist das Image fertig, wir müssen es nur noch ausführen. Die Übermittlung wird nach dem Booten kompiliert und ausgeführt.
  14. mkfifo /tmp/guest_output
  15. Öffnen Sie ein separates Terminal und warten Sie auf die Gastausgabe:

    dd if=/tmp/guest_output bs=1

  16. In einem anderen Terminal:

    qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput (Ich habe gerade den Ubuntu-Kernel hier verwendet, aber viele Kernel werden funktionieren)

  17. Wenn die Gastausgabe "BEREIT" anzeigt, können Sie über die qemu-Eingabeaufforderung Schlüssel an die VM senden. Um diese Zuordnung beispielsweise zu testen, können Sie dies tun

    (qemu) sendkey 1
    (qemu) sendkey 4
    (qemu) sendkey ret
    (qemu) sendkey 1
    (qemu) sendkey 0
    (qemu) sendkey ret
    (qemu) sendkey minus
    (qemu) sendkey 1
    (qemu) sendkey ret
    
  18. Jetzt Average = 12.000000sollte in der Gastausgabepipe angezeigt werden. Wenn nicht, ist der Schüler gescheitert.

  19. Qemu beenden: quit

Ein Programm, das den Test besteht, finden Sie hier: https://stackoverflow.com/a/14424295/309483 . Verwenden Sie einfach tcclib.hanstelle von stdio.h.

Janus Troelsen
quelle
5

Versuchen Sie Linux im Benutzermodus . Bei CPU-intensiven Jobs beträgt der Leistungsaufwand etwa 1%, bei E / A-intensiven Jobs kann er jedoch sechsmal langsamer sein.

pts
quelle
4

Firejail ist eines der umfassendsten Tools dafür - es unterstützt seccomp, Dateisystemcontainer, Funktionen und mehr:

https://firejail.wordpress.com/features-3/

Federico
quelle
Diese Antwort ist ausgezeichnet, sie verdient wirklich mehr positive Stimmen, wenn man bedenkt, dass das Feuergefängnis aktiv mit einer großartigen Dokumentation gepflegt wird, die meisten, wenn nicht alle anderen Antworten umfasst und relativ einfach zu bedienen ist.
Jeff Hykin
3

Das Ausführen in einer virtuellen Maschine sollte Ihnen alle gewünschten Sicherheits- und Einschränkungen bieten.

QEMU passt gut dazu, und die gesamte Arbeit (Herunterladen der Anwendung, Aktualisieren des Festplattenabbilds, Starten von QEMU, Ausführen der darin enthaltenen Anwendung und Speichern der Ausgabe zum späteren Abrufen) könnte für automatisierte Testläufe per Skript ausgeführt werden.

Laurent Parenteau
quelle
2
Ich weiß nichts über das OP, aber das Starten einer VM pro Testprogramm wäre in vielen Fällen nicht akzeptabel. In meiner Umgebung (ich bin ein TA) können bis zu 200 Studenten innerhalb von 2 Stunden jeweils 10-12 Programme einreichen. Kein Programm läuft länger als 10 Sekunden CPU-Zeit, aber wenn sich die Einreichungen häufen, erhalten wir Bearbeitungszeiten von 15 Minuten oder mehr. Die Einführung einer VM für jedes Programm würde die CPU-Zeit auf 60 Sekunden oder mehr pro Programm erhöhen, und ich möchte überhaupt nicht an die Durchlaufzeiten denken. Vielleicht eine VM pro Sitzung, aber auf keinen Fall könnten wir das pro Programm tun ...
thkala
@thkala Das ist ein guter Punkt. Ich mag die Idee von QEMU, aber das Starten einer VM für jede Einreichung ist nicht gut.
Frank
In diesem Fall muss immer dieselbe VM ausgeführt werden.
Laurent Parenteau
Könnten Sie etwas mit einem Snapshot einer VM tun, die alle gebootet und bereit ist, Code zu kompilieren und auszuführen? Zu Ihrer Information, VMs sind nicht unbedingt immun gegen Piercing. Sie können auch eine Hardwareversion davon erstellen - ein kleines System, das ein Resume-Image von schreibgeschützten Medien oder über das Netzwerk startet und die Ausgabe über das Netzwerk oder seriell bereitstellt und dann für das nächste System neu gestartet wird. Es gab einige schnelle Boot-Fortschritte, die Linux in wenigen Sekunden zum Laufen bringen.
Chris Stratton
@thkala: Das bedeutet, dass Sie weniger als 3 Sekunden pro Einreichung benötigen würden, wenn Sie sie seriell ausführen würden. Der Ansatz, den ich gepostet habe, dauert auf einer modernen Maschine (seriell) wahrscheinlich etwa 3 Sekunden. Wenn Sie parallelisieren (was Sie auch tun könnten), wäre es schnell genug.
Janus Troelsen
3

Wenn es um Sanboxing geht, basierend auf dem Check-out von ptrace (strace):

Sandbox " sydbox " und " pinktrace " “ Programmier - Bibliothek (es ist C99 , aber es gibt Bindungen zu Python und Ruby, soweit ich weiß).

Gesammelte Links zum Thema:

http://www.diigo.com/user/wierzowiecki/sydbox

(Entschuldigung, dass keine direkten Links, aber noch nicht genügend Reputationspunkte vorhanden sind)

Grzegorz Wierzowiecki
quelle
1

Diese Bibliothek sollte Ihrem Ziel gut dienen

http://sandbox.sourceforge.net

Viel Glück!

thoaionline
quelle
8
Dies scheint nicht aktiv aufrechterhalten zu werden. Es scheint auch einen Linux-Kernel-Patch zu erfordern, was es größtenteils nutzlos machen würde, wenn man bedenkt, dass seine neueste Version aus dem Jahr 2003 stammt.
thkala
1

Dies scheint auch vielversprechend. Eine Dateisystem-Sandbox für Linux, die Syscall-Intercepts verwendet.

https://github.com/adtac/fssb

mauron85
quelle
-1

ok dank all den Antworten, die sie mir sehr geholfen haben. Aber ich würde keinen von ihnen als Lösung für die Person vorschlagen, die die ursprüngliche Frage gestellt hat. Alle genannten Tools erfordern zu viel Arbeit, um den Code der Schüler als Lehrer, Tutor, Professor zu testen. Der beste Weg in diesem Fall wäre meiner Meinung nach virtualbox. Ok, es emuliert ein komplettes x68-System und hat auf diese Weise nichts mit der Bedeutung von Sandboxing zu tun, aber wenn ich mir meinen Programmierlehrer vorstelle, wäre es das Beste für ihn. "Apt-get install virtualbox" auf Debian-basierten Systemen, alle anderen gehen zu http://virtualbox.org/ , erstellen eine VM, fügen eine ISO hinzu, klicken auf "Installieren", warten Sie einige Zeit und haben Sie Glück. Es wird viel einfacher zu bedienen sein, um User-Mode-Linux einzurichten oder ein paar schwere Sachen zu machen ...

Und wenn Sie Angst haben, dass Ihre Schüler Sie hacken, haben Sie vermutlich ein Autoritätsproblem, und eine Lösung dafür würde ihnen drohen, dass Sie das lebendige Tageslicht aus ihnen herausklagen, wenn Sie nur einen Bissen Maleware in der Arbeit beweisen können, die sie geben Sie...

Auch wenn es eine Klasse gibt und 1% davon so gut ist, wie er solche Dinge tun könnte, langweile sie nicht mit so einfachen Aufgaben und gib ihnen einige große, wo sie noch mehr programmieren müssen. Integratives Lernen ist das Beste für alle, also verlassen Sie sich nicht auf alte festgefahrene Strukturen ...

Verwenden Sie natürlich niemals denselben Computer für wichtige Dinge (wie das Schreiben von Bescheinigungen und Prüfungen), die Sie zum Surfen im Internet und zum Testen von Software verwenden.

Verwenden Sie einen Offline-Computer für wichtige Dinge und einen Online-Computer für alle anderen Dinge.

Jedem anderen, der kein paranoider Lehrer ist (ich möchte niemanden beleidigen, ich bin nur der Meinung, dass Sie die Grundlagen über Sicherheit und unsere Gesellschaft lernen sollten, bevor Sie anfangen, Programmiererlehrer zu werden ...)

... wo war ich ... für alle anderen:

Viel Spaß beim Hacken !!

rohySeentrusted
quelle