Ich habe Systrace verwendet, um nicht vertrauenswürdige Programme sowohl interaktiv als auch im automatischen Modus zu sandboxen. Es hat einen ptrace()
-basiertes Backend, das die Verwendung auf einem Linux-System ohne besondere Berechtigungen ermöglicht, sowie ein viel schnelleres und leistungsfähigeres Backend, das ein Patchen des Kernels erfordert.
Es ist auch möglich, eine Sandbox auf Unix-ähnlichen Systemen mit chroot(1)
zu erstellen , obwohl das nicht ganz so einfach oder sicher ist. Linux-Container und FreeBSD-Jails sind eine bessere Alternative zu Chroot. Eine weitere Alternative unter Linux ist die Verwendung eines Sicherheitsframeworks wie SELinux oder AppArmor, was ich für Produktionssysteme vorschlagen würde.
Wir könnten Ihnen besser helfen, wenn Sie uns mitteilen, was genau 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, abhängig von Ihrer Distribution, eine eher standardmäßige und daher bevorzugte Alternative ist.
BEARBEITEN 2:
Während chroot(1)
auf den meisten (allen?) Unix-ähnlichen Systemen verfügbar ist, hat 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 besonders anfällig für dieses Problem. Und wenn Ihre Schüler auch nur annähernd wie meine sind, WIRD jemand versuchen, aus dem Gefängnis auszubrechen.
-
Sie müssen eine vollständig 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 notwendigen Update-Tools darin einbinden, was im Wesentlichen erfordern würde, dass es sich um eine vollwertige Linux-Distribution handelt. Außerdem müssen Sie System- und Benutzerdaten (Passwörter, Eingabedateien usw.) mit dem Hostsystem synchron halten.
-
chroot()
schützt nur das Dateisystem. Es verhindert nicht, dass ein bösartiges Programm Netzwerk-Sockets öffnet oder ein schlecht geschriebenes Programm jede verfügbare Ressource aufsaugt.
Das Ressourcennutzungsproblem ist allen Alternativen gemeinsam. Dateisystemquoten verhindern, dass Programme die Festplatte füllen. Richtiges ulimit
(setrlimit()
in C)-Einstellungen können vor Speicherüberlastung und Fork-Bomben schützen sowie CPU-Hogs stoppen. nice(1)
kann die Priorität dieser Programme herabsetzen, sodass der Computer problemlos für wichtigere Aufgaben verwendet werden kann.
Ich habe kürzlich einen Überblick über Sandboxing-Techniken unter Linux geschrieben. Ich denke, Ihr einfachster Ansatz wäre die Verwendung von Linux-Containern (lxc), wenn es Ihnen nichts ausmacht, sich zu verzweigen und so weiter, was in dieser Umgebung nicht wirklich wichtig ist. Sie können dem Prozess ein Nur-Lese-Root-Dateisystem und eine isolierte Loopback-Netzwerkverbindung geben, und Sie können ihn immer noch einfach beenden und Speichergrenzen usw. festlegen.
Seccomp wird etwas schwierig, da der Code nicht einmal Speicher zuweisen kann.
Selinux ist die andere Option, aber ich denke, es könnte mehr Arbeit als ein Container sein.
Sie können Qemu verwenden, um Aufgaben schnell zu testen. Dieser Vorgang dauert auf meinem 5 Jahre alten Laptop weniger als 5 Sekunden.
Nehmen wir an, der Student muss ein Programm entwickeln, das unsigned ints nimmt, jedes auf seiner eigenen Zeile, bis eine Zeile mit "-1" ankommt. Das Programm sollte dann alle Ints mitteln und "Average:%f" ausgeben. So können Sie das Programm vollständig isoliert testen:
-
Holen Sie sich zuerst
root.bin
von Jslinux verwenden wir das als Userland (es hat den tcc C-Compiler):wget https://github.com/levskaya/jslinux-deobfuscated/raw/master/root.bin
-
Wir möchten die Einreichung des Schülers in
root.bin
stellen , richten Sie also 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, brauchen Sie für nichts davon root)
-
Erstellen Sie ein leeres Verzeichnis:
mkdir mountpoint
-
Montieren Sie
root.bin
:sudo mount /dev/loop0 mountpoint
-
Geben Sie das gemountete Dateisystem ein:
cd mountpoint
. -
Rechte korrigieren:
sudo chown -R `whoami` .
mkdir -p etc/init.d
-
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
-
chmod +x etc/init.d/rcS
-
Kopieren Sie die Übermittlung in die VM:
cp ~/student_assignment.c root/assignment.c
-
Beenden Sie das Root-FS der VM:
cd ..
sudo umount mountpoint
- Nun ist das Image fertig, wir müssen es nur noch ausführen. Es wird die Übermittlung nach dem Booten kompilieren und ausführen.
mkfifo /tmp/guest_output
-
Öffnen Sie ein separates Terminal und beginnen Sie mit dem Lauschen auf Gastausgaben:
dd if=/tmp/guest_output bs=1
-
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 hier nur den Ubuntu-Kernel verwendet, aber viele Kernel werden funktionieren) -
Wenn die Gastausgabe „READY“ anzeigt, können Sie von der qemu-Eingabeaufforderung aus Schlüssel an die VM senden. Um diese Zuweisung beispielsweise zu testen, können Sie Folgendes 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
-
Jetzt
Average = 12.000000
sollte auf der Guest-Ausgangsleitung erscheinen. Wenn dies nicht der Fall ist, ist der Schüler durchgefallen. - qemu beenden:
quit
Ein Programm, das den Test besteht, finden Sie hier:https://stackoverflow.com/a/14424295/309483. Verwenden Sie einfach tcclib.h
statt stdio.h
.