Eseguire un programma C non attendibile in una sandbox in Linux che gli impedisce di aprire file, fork, ecc.?


110

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

Sarebbe un piccolo programma, un compito a casa, che viene caricato su un server e su cui vengono eseguiti test unitari. Quindi il programma sarebbe di breve durata.


È come un singolo programma C che devi eseguire 1 volta per 5 minuti o qualcosa che devi eseguire costantemente?
bwawok

Sarebbe un piccolo programma che viene caricato e su cui vengono eseguiti gli unit test. Quindi il programma sarebbe di breve durata.
Frank,

Quale distribuzione utilizza il sistema? Alcune distribuzioni hanno strumenti già pronti per il sandboxing. Il tuo sistema ha un modello di sicurezza come SELinux o AppArmor abilitato?
thkala

Sto usando Fedora 13. Sto esaminando la policy di SELinux Sandbox. Mi chiedo quali altre opzioni esistono.
Frank

Risposte:


47

Ho usato Systrace per sandbox programmi non attendibili sia in modo interattivo che in modalità automatica. Ha un ptrace()backend basato su che ne consente l'uso su un sistema Linux senza privilegi speciali, così come un backend molto più veloce e potente che richiede l'applicazione di patch al kernel.

È anche possibile creare una sandbox su sistemi simili a Unix utilizzando chroot(1), sebbene non sia altrettanto facile o sicuro. I contenitori Linux e le jail di FreeBSD sono un'alternativa migliore al chroot. Un'altra alternativa su Linux è usare un framework di sicurezza come SELinux o AppArmor , che è quello che proporrei per i sistemi di produzione.

Saremmo in grado di aiutarti di più se dicessi cosa esattamente vuoi fare.

MODIFICARE:

Systrace funzionerebbe 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:

Sebbene chroot(1)sia disponibile sulla maggior parte (tutti?) Dei sistemi Unix, presenta alcuni problemi:

  • Può essere rotto. Se hai intenzione di compilare o eseguire effettivamente programmi C non attendibili sul tuo sistema, sei particolarmente vulnerabile a questo problema. E se i tuoi studenti sono qualcosa come i miei, qualcuno cercherà di evadere dalla prigione.

  • Devi creare una gerarchia di filesystem completamente indipendente con tutto ciò che è necessario per il tuo compito. Non è necessario avere un compilatore nel chroot, ma dovrebbe essere incluso tutto ciò che è necessario per eseguire i programmi compilati. Sebbene ci siano utilità che aiutano con questo, non è ancora banale.

  • Devi mantenere il chroot. Poiché è indipendente, i file chroot non verranno aggiornati insieme alla distribuzione. Dovrai ricreare il chroot regolarmente o includervi gli strumenti di aggiornamento necessari, il che richiederebbe essenzialmente che si tratti di una distribuzione Linux in piena regola. Dovrai anche mantenere i dati di sistema e utente (password, file di input, ecc.) Sincronizzati con il sistema host.

  • chroot()protegge solo il filesystem. Non impedisce a un programma dannoso di aprire socket di rete oa un programma mal scritto di aspirare ogni risorsa disponibile.

Il problema dell'utilizzo delle risorse è comune a tutte le alternative. Le quote del filesystem impediranno ai programmi di riempire il disco. Impostazioni corrette ulimit( setrlimit()in C) possono proteggere dall'uso eccessivo della memoria e da eventuali fork bomb, oltre a porre fine ai divoratori della CPU. nice(1)può abbassare la priorità di quei programmi in modo che il computer possa essere utilizzato per qualsiasi attività ritenuta più importante senza problemi.


systrace ha funzionato per me per programmi semplici, ma è rimasto bloccato indefinitamente quando GNU come (1) come eseguito da GCC. Quindi ho rinunciato. È un bug non risolto in systrace: forum.soft32.com/linux/…
punti

Esiste un modo per garantire che la memoria condivisa, le code di messaggi e i semafori non siano condivisi tra i processi in modalità sandbox?
daveagp

1
Il collegamento di systrace è interrotto.
Collin

2
Che mi dici di Firejail? Non devi più mantenere il fs usandolo.
m3nda

18

Di recente ho scritto una panoramica delle tecniche di sandboxing in Linux . Penso che il tuo approccio più semplice sarebbe usare i contenitori Linux (lxc) se non ti importa del fork e così via, cosa che non ha molta importanza 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, poiché il codice non può nemmeno allocare memoria.

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


6

Puoi utilizzare Qemu per testare rapidamente i compiti. La procedura seguente richiede meno di 5 secondi sul mio laptop di 5 anni.

Supponiamo che lo studente debba sviluppare un programma che accetta interi senza segno, ciascuno sulla propria riga, finché non arriva una riga con "-1". Il programma dovrebbe quindi calcolare la media di tutti gli int e restituire "Media:% f". Ecco come puoi testare un programma completamente isolato:

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

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

  2. Vogliamo inserire la presentazione dello studente root.bin, quindi configura il dispositivo loop:

    sudo losetup /dev/loop0 root.bin

    (potresti usare fuseext2 anche 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. Montare root.bin:

    sudo mount /dev/loop0 mountpoint

  5. Entra nel filesystem montato:

    cd mountpoint.

  6. Diritti di correzione:

    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 FS della VM:

    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 degli ospiti:

    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", è possibile inviare le chiavi alla VM dal prompt di qemu. Ad esempio, per testare questo compito, 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.000000dovrebbe apparire sulla pipe di output del guest. In caso contrario, lo studente ha fallito.

  19. Esci da qemu: quit

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


5

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


4

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

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


Questa risposta è eccellente, merita davvero più voti positivi considerando che Firejail è attivamente mantenuto con un'ottima documentazione, comprende la maggior parte se non tutte le altre risposte ed è progettato per essere relativamente facile da usare.
Jeff Hykin

3

L'esecuzione all'interno di una macchina virtuale dovrebbe offrirti tutta la sicurezza e le restrizioni che desideri.

QEMU sarebbe una buona soluzione per questo e tutto il lavoro (scaricare l'applicazione, aggiornare l'immagine del disco, avviare QEMU, eseguire l'applicazione al suo interno e salvare l'output per un successivo recupero) potrebbe essere programmato per l'esecuzione di test automatizzati.


2
Non so dell'OP, ma in molti casi l'avvio di una VM per programma di test sarebbe inaccettabile. Nel mio ambiente (sono un assistente tecnico) ci possono essere fino a 200 studenti che inviano 10-12 programmi ciascuno in un periodo di 2 ore. Nessun programma viene eseguito per più di 10 secondi di tempo CPU, ma quando gli invii si accumulano otteniamo tempi di risposta di 15 minuti o più. L'introduzione di una VM per ogni programma spingerebbe il tempo della CPU a 60 secondi o più per programma e non voglio affatto pensare ai tempi di risposta. Forse una VM per sessione, ma in nessun modo potremmo farlo per programma ...
thkala

@thkala Questo è un buon punto. Mi piace l'idea di QEMU ma avviare una VM per ogni invio non va bene.
Frank

Bene, in quel caso, mantieni la stessa VM sempre in esecuzione.
Laurent Parenteau

Potresti fare qualcosa usando un'istantanea di una macchina virtuale che è stata avviata e pronta per compilare ed eseguire codice? Cordiali saluti, le vm non sono necessariamente immuni al piercing. Potresti anche creare una versione hardware di questo: un piccolo sistema che avvia un'immagine di ripresa da un supporto di sola lettura o sulla rete e fornisce l'output tramite rete o seriale, quindi viene riavviato per il prossimo. Ci sono stati alcuni rapidi progressi nell'avvio che hanno riavviato Linux in pochi secondi.
Chris Stratton

@thkala: Ciò significa che avresti bisogno di meno di 3 secondi per invio se li eseguissi in serie. L'approccio che ho pubblicato richiede probabilmente circa 3 secondi su una macchina moderna (in serie). Se parallelizzi (cosa che potresti fare anche tu) sarebbe abbastanza veloce.
Janus Troelsen

3

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

" Sydbox sandbox" e " pinktrace " Programmazione biblioteca (è C99, ma ci sono attacchi a Python e Ruby per quanto ne so).

Collegamenti raccolti relativi all'argomento:

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

(mi dispiace che non ci siano collegamenti diretti, ma ancora non ci sono abbastanza punti reputazione)



1

Questa libreria dovrebbe servire bene al tuo obiettivo

http://sandbox.sourceforge.net

In bocca al lupo!


8
Questo non sembra essere mantenuto attivamente. Sembra anche richiedere una patch del kernel Linux, il che lo renderebbe perlopiù inutile considerando che la sua ultima versione risale al 2003.
thkala


-1

ok grazie a tutte le risposte mi hanno aiutato molto. Ma non 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 x68 completo e non ha nulla a che fare con il significato di sandbox 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 vanno su http://virtualbox.org/ , creano un vm, aggiungono un iso, fanno clic su installa, aspetta un po 'di tempo e sii fortunato. Sarà molto più facile da usare come impostare la modalità utente-linux o fare alcune cose pesanti di strace ...

E se hai paura che i tuoi studenti ti hackerino, immagino che tu abbia un problema di autorità e una soluzione per questo sarebbe minacciarli di far loro causa contro la luce del giorno se riesci a dimostrare solo un morso di maleware nel lavoro che danno tu...

Inoltre, se c'è una classe e l'1% di essa è buono come lui potrebbe fare queste cose, non annoiarli con compiti così semplici e dargli alcuni grandi in cui devono codificare ancora un po '. L'apprendimento integrativo è la cosa migliore per tutti, quindi non fare affidamento su vecchie strutture bloccate ...

E ovviamente, non usare mai lo stesso computer per cose importanti (come scrivere attestati ed esami), che stai usando per cose come navigare sul web e testare software.

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

Tuttavia a tutti gli altri che non sono un insegnante paranoico (non voglio offendere nessuno, sono solo dell'opinione che dovresti imparare le basi sulla sicurezza e sulla nostra società prima di iniziare a essere un insegnante di programmatori ...)

... dov'ero io ... per tutti gli altri:

felice hacking !!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.