
Esecuzione sicura del codice
CodeJail gestisce l'esecuzione di codice non attendibile in sandbox sicure. È progettato principalmente per l'esecuzione di Python, ma può essere utilizzato anche per altri linguaggi.
La sicurezza è applicata tramite AppArmor. Se il tuo sistema operativo non supporta AppArmor, o se il profilo AppArmor non è definito e configurato correttamente, CodeJail non proteggerà l'esecuzione.
CodeJail è progettato per essere configurabile e si auto-configurerà per l'esecuzione di Python se lo installi correttamente.
Una sandbox CodeJail è composta da diversi elementi:
#) Ambiente sandbox. Per una configurazione Python, questo sarebbe Python e i pacchetti core associati come virtualenv. Nel presente documento viene indicato come . È di sola lettura e condiviso tra le istanze della sandbox.
Il codice in sandbox ha inoltre accesso alle librerie di sistema nella misura in cui il profilo AppArmor lo consente.
#) Directory di esecuzione della sandbox. Si tratta di una directory effimera di sola lettura denominata come /tmp/codejail-XXXXXXXX contenente il codice inviato (./jailed_code), eventuali file aggiuntivi e una directory temporanea scrivibile (./tmp) che il codice inviato può utilizzare come area di lavoro temporanea.
Il codice inviato è tipicamente il codice presentato dallo studente per essere testato sul server, e i file aggiuntivi sono tipicamente un python_lib.zip contenente librerie di valutazione o utilità.
Per funzionare, CodeJail richiede due account utente. Un account è l'account principale sotto il quale il codice viene eseguito, che ha accesso per creare sandbox. Verrà indicato come <SANDBOX_CALLER>. Il secondo account è quello sotto il quale viene eseguita la sandbox. Tipicamente si tratta dell'account sandbox.
Questa libreria è attualmente testata per funzionare con le seguenti versioni:
Python:
Ubuntu:
(Nota che la versione di Python utilizzata all'interno della sandbox potrebbe essere diversa dalla versione utilizzata per la libreria stessa.)
Queste istruzioni descrivono come configurare il sistema operativo affinché CodeJail possa eseguire codice Python in modo sicuro. Tuttavia, è anche possibile impostare codejail.safe_exec.ALWAYS_BE_UNSAFE = True ed eseguire il Python inviato direttamente sulla macchina, senza alcuna sicurezza. Questo può andare bene per le macchine degli sviluppatori che non sono preoccupati dalla sicurezza e consente di testare un'integrazione con l'API di CodeJail. Non deve essere utilizzato se qualsiasi input proviene da fonti non attendibili. Non utilizzare questa opzione in sistemi di produzione.
Per proteggere l'esecuzione di Python, creerai una nuova virtualenv. Ciò significa che ne avrai due: la virtualenv principale per il tuo progetto e quella nuova per il codice Python in sandbox.
Scegli un posto per la nuova virtualenv e chiamala . Verrà rilevata e utilizzata automaticamente se la metti subito accanto alla tua virtualenv esistente, ma con -sandbox aggiunto. Quindi, se la tua virtualenv esistente si trova in /home/chris/ve/myproj, fai sì che sia /home/chris/ve/myproj-sandbox.
L'utente che esegue l'LMS è <SANDBOX_CALLER>, ad esempio tu sulla tua macchina di sviluppo, oppure www-data su un server.
Altri dettagli che dipendono dalla tua configurazione:
Crea la nuova virtualenv, usando --copies in modo che ci sia un eseguibile Python distinto da limitare::
$ sudo python3.12 -m venv --copies
Per impostazione predefinita, la virtualenv creerebbe semplicemente un collegamento simbolico al Python di sistema, e la configurazione predefinita di apparmor su alcuni sistemi operativi potrebbe impedire che il confinamento venga applicato.
(Opzionale) Se hai pacchetti particolari che vuoi rendere disponibili al tuo codice in sandbox, installali attivando la virtual env della sandbox e usando pip per installarli::
$ /bin/pip install -r requirements/sandbox.txt
Aggiungi un utente sandbox::
$ sudo addgroup sandbox $ sudo adduser --disabled-login sandbox --ingroup sandbox
Consenti al server web di eseguire il Python in sandbox come sandbox. Crea il file /etc/sudoers.d/01-sandbox::
$ sudo visudo -f /etc/sudoers.d/01-sandbox
<SANDBOX_CALLER> ALL=(sandbox) SETENV:NOPASSWD:/bin/python <SANDBOX_CALLER> ALL=(sandbox) SETENV:NOPASSWD:/usr/bin/find <SANDBOX_CALLER> ALL=(ALL) NOPASSWD:/usr/bin/pkill
(Nota che il binario find può eseguire codice arbitrario, quindi questo non è un file sudoers sicuro per scopi non codejail.)
Modifica un profilo AppArmor. Si tratta di un file di testo che specifica i limiti per l'eseguibile Python in sandbox. Il file deve trovarsi in /etc/apparmor.d e dovrebbe essere nominato in base all'eseguibile, con gli slash sostituiti da punti. Ad esempio, se il tuo Python in sandbox si trova in /home/chris/ve/myproj-sandbox/bin/python, allora il tuo profilo AppArmor deve essere /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python.
Se il tuo CodeJail è configurato correttamente per usare safe_exec, prova questi comandi nel tuo terminale Python::
import codejail.jail_code
codejail.jail_code.configure('python', '<SANDENV>/bin/python', user='sandbox')
import codejail.safe_exec
jailed_globals = {}
codejail.safe_exec.safe_exec("output=open('/etc/passwd').read()", jailed_globals)
print(jailed_globals) # should be unreachable if codejail is working properly
Questo dovrebbe fallire con un'eccezione.
Se hai bisogno di modificare i pacchetti installati nella virtualenv della tua sandbox, dovrai disabilitare AppArmor, perché il tuo Python in sandbox non ha i diritti per modificare i file nella sua directory site-packages.
Disabilita AppArmor per la tua sandbox::
$ sudo apt-get install apparmor-utils # if you haven't already $ sudo aa-complain /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Installa o modifica in altro modo i pacchetti installati::
$ pip install -r requirements/sandbox.txt
Riattiva AppArmor per la tua sandbox::
$ sudo aa-enforce /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Per eseguire i test, devi completare i passaggi di installazione standard. Poi devi impostare le seguenti variabili d'ambiente::
$ export CODEJAIL_TEST_USER=<owner of sandbox (usually 'sandbox')>
$ export CODEJAIL_TEST_VENV=<SANDENV>
Esegui i test con il Makefile::
$ make tests
Diversi test proxy vengono saltati se la modalità proxy non è configurata.
CodeJail è abbastanza generico da poter essere utilizzato in una varietà di progetti per eseguire codice non attendibile. Fornisce due livelli:
jail_code.py offre un'esecuzione sicura dei subprocessi. Lo fa eseguendo il programma in un subprocess gestito da AppArmor.
safe_exec.py offre una gestione specializzata dell'esecuzione di Python, usando jail_code per fornire la semantica dell'istruzione exec di Python.
CodeJail esegue i programmi sotto AppArmor. AppArmor è una funzionalità fornita dal sistema operativo per limitare le risorse a cui i programmi possono accedere. Per eseguire codice Python con accesso limitato alle risorse, creiamo una nuova virtualenv, poi indichiamo quell'eseguibile Python in un profilo AppArmor e limitiamo le risorse in quel profilo. CodeJail eseguirà il programma Python fornito con quell'eseguibile e AppArmor limiterà automaticamente le risorse a cui può accedere. CodeJail usa anche setrlimit per limitare la quantità di tempo CPU e/o memoria disponibile al processo.
codejail.jail_code accetta un programma da eseguire, i file da copiare nel suo ambiente, gli argomenti della riga di comando e uno stream stdin. Crea una directory temporanea, crea o copia i file necessari, avvia un subprocess per eseguire il codice e restituisce l'output e lo stato di uscita del processo.
codejail.safe_exec emula l'istruzione exec di Python. Prende un blocco di codice Python e lo esegue usando jail_code, modificando il dizionario dei globals come effetto collaterale. safe_exec fa questo serializzando i globals dentro e fuori dal subprocess come JSON.
Se codejail o AppArmor non è configurato correttamente, codejail potrebbe impostare come predefinito l'esecuzione insicura del codice (senza sandbox). Non è sicuro per impostazione predefinita. I progetti che integrano codejail dovrebbero considerare di includere una suite di test runtime che verifichi il corretto confinamento all'avvio prima che vengano accettati input non attendibili.
L'isolamento della sandbox è ottenuto tramite il confinamento AppArmor. Codejail facilita questo processo, ma non può isolare l'esecuzione senza l'uso di AppArmor.
I limiti delle risorse possono essere vincolati solo usando i meccanismi che l'rlimit di Linux mette a disposizione. Alcune carenze notevoli:
Sebbene FSIZE di rlimit possa limitare la dimensione di ogni singolo file che un processo può creare e possa limitare il numero di file aperti in un dato momento, non può limitare il numero totale di file scritti e quindi non può limitare il numero totale di byte scritti su tutti i file. Una mitigazione parziale consiste nel vincolare il tempo massimo di esecuzione. (Tutti i file scritti nella sandbox verranno eliminati al termine dell'esecuzione, in ogni caso.)
Il limite NPROC vincola la capacità del processo corrente di creare nuovi thread e processi, ma il conteggio di utilizzo (quanti processi esistono già) è la somma su tutti i processi con lo stesso UID, anche in altri container sullo stesso host dove l'UID potrebbe essere mappato a un nome utente diverso. Questo vincolo si applica anche all'utente dell'app a causa di come vengono applicati i rlimit. Anche se vengono scelti UID che non sono usati da altri software sull'host, più processi sandbox codejail sullo stesso host condivideranno questo pool di utilizzo e possono ridurre reciprocamente la capacità di creare processi. In questa situazione, NPROC dovrà essere impostato più alto di quanto sarebbe per una singola istanza codejail che gestisce una singola richiesta alla volta.
Le sandbox non hanno un forte isolamento tra loro. Con una configurazione corretta, il codice non attendibile non dovrebbe essere in grado di scoprire altre esecuzioni di codice attive, ma se questa ipotesi viene violata, una sandbox potrebbe teoricamente interferire con un'altra.
Non segnalare problemi di sicurezza pubblicamente. Invia un'email a [email protected].
Vedi il profilo di esempio in apparmor-profiles/. Il profilo deve essere personalizzato per corrispondere alla posizione della tua sandbox.
Analizza i profili::
$ sudo apparmor_parser --replace --warn=all --warn=no-debug-cache --Werror <APPARMOR_FILE>
Riattiva di nuovo la virtualenv principale del tuo progetto.
Disabilita l'uso di PAM per impostare i rlimit::
sed -i '/pam_limits.so/d' /etc/pam.d/sudo