Eseguire un programma C non attendibile in una sandbox in Linux che impedisca l’apertura di file, forking, ecc.?

Mi chiedevo se esiste un modo per eseguire un programma C non affidabile sotto una sandbox in Linux. Qualcosa che impedirebbe al programma di aprire file, connessioni di rete o forking, exec, ecc.?

Sarebbe un piccolo programma, un compito a casa, che viene caricato su un server e ha eseguito test unitari su di esso. Quindi il programma sarebbe di breve durata.

Ho usato Systrace per sandbox programmi non affidabili sia intertriggersmente che in modalità automatica. Ha un backend basato su ptrace() che ne consente l’uso su un sistema Linux senza privilegi speciali, oltre a un backend molto più veloce e più potente che richiede l’applicazione di patch al kernel.

È anche ansible creare una sandbox su sistemi di tipo Unix usando chroot(1) , anche se non è così facile o sicuro. I contenitori Linux e le jail di FreeBSD sono un’alternativa migliore a chroot. Un’altra alternativa su Linux è quella di utilizzare un framework di sicurezza come SELinux o AppArmor , che è quello che proporrei per i sistemi di produzione.

Saremo in grado di aiutarti di più se hai detto come esattamente ciò che vuoi fare.

MODIFICARE:

Systrace potrebbe funzionare per il tuo caso, ma penso che qualcosa basato sul modello di sicurezza Linux come AppArmor o SELinux sia un’alternativa più standard, e quindi preferita, a seconda della tua distribuzione.

MODIFICA 2:

Mentre chroot(1) è disponibile sulla maggior parte (tutti?) Dei sistemi Unix, ha alcuni problemi:

  • Può essere rotto da Se si sta effettivamente compilando o eseguendo programmi C non attendibili sul proprio sistema, si è particolarmente vulnerabili a questo problema. E se i tuoi studenti sono come i miei, qualcuno cercherà di uscire dal carcere.

  • Devi creare una gerarchia di filesystem completa e indipendente con tutto ciò che è necessario per il tuo compito. Non è necessario avere un compilatore in chroot, ma è necessario includere tutto ciò che è necessario per eseguire i programmi compilati. Mentre ci sono programmi di utilità che aiutano con questo, non è ancora banale.

  • Devi mantenere il chroot. Poiché è indipendente, i file chroot non verranno aggiornati insieme alla tua distribuzione. Dovrai ricreare il chroot regolarmente o includere gli strumenti di aggiornamento necessari al suo interno, il che richiede essenzialmente che si tratti di una distribuzione Linux completa. Dovrai inoltre mantenere i dati di sistema e dell’utente (password, file di input, ecc.) Sincronizzati con il sistema host.

  • chroot() protegge solo il filesystem. Non impedisce a un programma malevolo di aprire socket di rete o uno mal scritto dal risucchiamento di tutte le risorse disponibili.

Il problema dell’utilizzo delle risorse è comune tra tutte le alternative. Le quote del filesystem impediranno ai programmi di riempire il disco. Le impostazioni corrette di ulimit ( setrlimit() in C) possono proteggere dall’uso eccessivo della memoria e da eventuali fork bomb e anche da fermare gli hog della CPU. nice(1) può ridurre la priorità di quei programmi in modo che il computer possa essere utilizzato per qualsiasi compito ritenuto più importante senza problemi.

Di recente ho scritto una panoramica delle tecniche di sandboxing in Linux . Penso che il tuo approccio più semplice sarebbe quello di usare contenitori Linux (lxc) se non ti preoccupi del biforcarsi e così via, cosa che non importa in questo ambiente. Puoi dare al processo un file system root di sola lettura, una connessione di rete loopback isolata, e puoi comunque ucciderlo facilmente e impostare limiti di memoria, ecc.

Seccomp sarà un po ‘difficile, in quanto il codice non può nemmeno allocare memoria.

Selinux è l’altra opzione, ma penso che potrebbe essere più lavoro di un contenitore.

Puoi usare Qemu per testare rapidamente i compiti. Questa procedura di seguito richiede meno di 5 secondi sul mio portatile di 5 anni.

Supponiamo che lo studente debba sviluppare un programma che tenga valori non firmati, ciascuno sulla propria linea, fino a quando arriva una riga con “-1”. Il programma dovrebbe quindi calcolare la media di tutti gli input e l’output “Average:% f”. Ecco come puoi testare il programma completamente isolato:

  1. Per prima cosa, ottieni root.bin da Jslinux, lo useremo come userland (ha il compilatore C tcc):

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

  2. Vogliamo inserire l’invio dello studente in root.bin , quindi imposta il dispositivo loop:

    sudo losetup /dev/loop0 root.bin

    (puoi usare anche fuseext2 per questo, ma non è molto stabile.Se si stabilizza, non avrai bisogno di root per niente di tutto questo)

  3. Crea una directory vuota:

    mkdir mountpoint

  4. Monta root.bin :

    sudo mount /dev/loop0 mountpoint

  5. Inserisci il filesystem montato:

    cd mountpoint .

  6. Correzione dei diritti:

    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. Copia l’invio alla VM:

    cp ~/student_assignment.c root/assignment.c

  11. Esci dalla radice della macchina virtuale:

    cd ..

  12. sudo umount mountpoint
  13. Ora l’immagine è pronta, dobbiamo solo eseguirla. Compilerà ed eseguirà l’invio dopo l’avvio.
  14. mkfifo /tmp/guest_output
  15. Apri un terminale separato e inizia ad ascoltare l’output del guest:

    dd if=/tmp/guest_output bs=1

  16. In un altro terminale:

    qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput (Ho appena usato il kernel di Ubuntu qui, ma molti kernel funzioneranno)

  17. Quando l’output del guest mostra “READY”, è ansible inviare le chiavi alla VM dal prompt qemu. Ad esempio, per testare questo incarico, potresti farlo

     (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. Ora Average = 12.000000 dovrebbe apparire sulla pipe di output del guest. In caso contrario, lo studente ha fallito.

  19. Esci da qemu: quit

Un programma che passa il test è qui: https://stackoverflow.com/a/14424295/309483 . Basta usare tcclib.h invece di stdio.h .

Prova Linux in modalità utente . Ha un sovraccarico delle prestazioni di circa l’1% per i lavori che richiedono un utilizzo intensivo della CPU, ma potrebbe essere 6 volte più lento per i lavori ad alta intensità di I / O.

Eseguirlo all’interno di una macchina virtuale dovrebbe offrirti tutta la sicurezza e le restrizioni che desideri.

QEMU sarebbe adatto per questo e tutto il lavoro (scaricando l’applicazione, aggiornando l’immagine del disco, avviando QEMU, eseguendo l’applicazione al suo interno e salvando l’output per il successivo recupero) potrebbe essere programmato per le prove automatizzate.

Quando si tratta di sanboxing basato su ptrace (strace) check-out:

sandbox ” sydbox ” e libreria di programmazione ” pinktrace ” (è C99 ma ci sono legami con Python e Ruby per quanto ne so).

Link raccolti relativi all’argomento:

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

(mi dispiace che non i link diretti, ma non ci sono ancora abbastanza punti reputazione)

seccomp e seccomp-bpf eseguono questo con il minimo sforzo: https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt

Firejail è uno degli strumenti più completi per farlo: supporta seccomp, contenitori per filesystem, funzionalità e altro:

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

Questa libreria dovrebbe servire bene il tuo objective

http://sandbox.sourceforge.net

In bocca al lupo!

Anche questo sembra promettente. Una sandbox del filesystem per Linux che usa le intercettazioni di syscall.

https://github.com/adtac/fssb

ok grazie a tutte le risposte che mi hanno aiutato molto. Ma io suggerirei nessuno di loro come soluzione per la persona che ha posto la domanda originale. Tutti gli strumenti menzionati richiedono molto lavoro allo scopo di testare il codice degli studenti come insegnante, tutor, prof. Il modo migliore in questo caso sarebbe a mio parere virtualbox. Ok, emula un sistema completo x68 e non ha nulla a che fare con il significato di sandboxing in questo modo, ma se immagino il mio insegnante di programmazione sarebbe il migliore per lui. Quindi “apt-get install virtualbox” su sistemi basati su debian, tutti gli altri si dirigono su http://virtualbox.org/ , creano un vm, aggiungono un iso, fanno clic su installa, aspettano un po ‘di tempo e sono fortunati. Sarà molto più facile da usare come configurare user-mode-linux o fare alcune cose pesanti strace …

E se hai paura che i tuoi studenti ti hackerino, credo che tu abbia un problema di autorità e una soluzione per loro sarebbe una minaccia per loro che citeresti in giudizio le luci viventi se riesci a provare solo un morso di maleware nel lavoro che danno tu…

Inoltre, se c’è una class e l’1% di esso è buono come lui potrebbe fare cose del genere, non annoiarli con compiti così semplici e dargli alcuni grandi in cui devono codificarne altri. L’apprendimento integrativo è la cosa migliore per tutti, quindi non ricorrere a vecchie strutture in stallo …

E di causa, non usare mai lo stesso computer per cose importanti (come la stesura di attestati e esami), che stai usando per cose come navigare sul web e testare il software.

Usa un computer offline per cose importanti e un computer online per tutte le altre cose.

Comunque per chiunque non sia un insegnante paranoico (non voglio offendere nessuno, sono solo dell’opinione che dovresti imparare le basi della sicurezza e della nostra società prima di iniziare a diventare un insegnante di programmatori …)

… dove ero io … per tutti gli altri:

felice hacking !!