GNU/Linux >> Linux Esercitazione >  >> Linux

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

Ho utilizzato Systrace per eseguire il sandbox di programmi non attendibili sia in modo interattivo che in modalità automatica. Ha un ptrace() -based backend che ne consente l'utilizzo su un sistema Linux senza privilegi speciali, oltre a 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 usando chroot(1) , anche se non è altrettanto facile o sicuro. I container Linux e le jail di FreeBSD sono un'alternativa migliore a chroot. Un'altra alternativa su Linux è utilizzare 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 esattamente cosa vuoi fare.

MODIFICA:

Systrace funzionerebbe per il tuo caso, ma penso che qualcosa basato sul Linux Security Model 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 simili a Unix, presenta alcuni problemi:

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

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

  • Devi mantenere il chroot. Poiché è indipendente, i file chroot non verranno aggiornati insieme alla tua distribuzione. Dovrai ricreare regolarmente il chroot o includere gli strumenti di aggiornamento necessari, il che richiederebbe essenzialmente che si tratti di una distribuzione Linux completa. Dovrai anche mantenere i dati di sistema e utente (password, file di input e.t.c.) sincronizzati con il sistema host.

  • chroot() protegge solo il filesystem. Non impedisce a un programma dannoso di aprire socket di rete o a uno scritto male di risucchiare 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. Corretto ulimit (setrlimit() in C) le impostazioni possono proteggere dall'uso eccessivo della memoria e da eventuali fork bomb, oltre a porre fine ai maiali 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.


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 dispiace biforcare e così via, che non ha molta importanza in questo ambiente. Puoi dare al processo un file system root di sola lettura, una connessione di rete di loopback isolata e puoi ancora ucciderlo facilmente e impostare limiti di memoria, ecc.

Seccomp sarà un po' difficile, dato che il codice non può nemmeno allocare memoria.

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


Puoi usare Qemu per testare rapidamente gli incarichi. Questa procedura di seguito 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 fare la media di tutti gli interi e produrre "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 la consegna dello studente in root.bin , quindi configura il dispositivo loop:

    sudo losetup /dev/loop0 root.bin

    (puoi 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. Monta root.bin :

    sudo mount /dev/loop0 mountpoint

  5. Inserisci il filesystem montato:

    cd mountpoint .

  6. Correggi i 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 dal root 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 dell'ospite:

    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", puoi inviare le chiavi alla VM dal prompt di qemu. Ad esempio, per testare questa assegnazione, potresti fare

    (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 supera il test è qui:https://stackoverflow.com/a/14424295/309483. Basta usare tcclib.h invece di stdio.h .


Linux
  1. Come creare un video da file PDF in Linux

  2. Linux:come eseguire un bootloader da Linux?

  3. Linux:quali dati devono essere esclusi da file di registro, messaggi di errore ecc. Se pubblicati online?

  4. Migrazione di un server Linux dalla riga di comando

  5. Come eseguo un programma con una directory di lavoro diversa da quella corrente, dalla shell di Linux?

Configurazione Linux:comprensione delle directory *.d in /etc

Come scaricare file da server Linux remoti

I 20 migliori comandi Linux Vim che aumentano la produttività

Modi brillanti su come eseguire un programma in Linux

Come scrivere ed eseguire un programma C in Linux

Come eseguire il comando SUDO in WinSCP per trasferire file da Windows a Linux