
Execução segura de código
========
O CodeJail gerencia a execução de código não confiável em sandboxes seguros. Ele é projetado principalmente para execução de Python, mas também pode ser usado para outras linguagens.
A segurança é aplicada com AppArmor. Se o seu sistema operacional não suportar AppArmor, ou se o perfil do AppArmor não estiver definido e configurado corretamente, o CodeJail não protegerá a execução.
O CodeJail é projetado para ser configurável e se auto-configura para execução de Python se você o instalar corretamente.
Um sandbox do CodeJail consiste em várias partes:
#) Ambiente do sandbox. Para uma configuração Python, isso seria o Python e os pacotes principais associados como um virtualenv. Isso é indicado ao longo deste documento como . Ele é somente leitura e compartilhado entre as instâncias do sandbox.
O código em sandbox também tem acesso às bibliotecas do sistema operacional na medida em que o perfil do AppArmor permitir.
#) Diretório de execução do sandbox. Este é um diretório efêmero somente
leitura nomeado como /tmp/codejail-XXXXXXXX contendo o código enviado
(./jailed_code), arquivos adicionais opcionais e um diretório temporário
gravável (./tmp) que o código enviado pode usar como espaço de trabalho
temporário.
O código enviado é tipicamente o código submetido pelo estudante para ser
testado no servidor, e os arquivos adicionais são tipicamente um
python_lib.zip contendo bibliotecas de avaliação ou utilitárias.
Para executar, o CodeJail requer duas contas de usuário. Uma conta é a conta
principal sob a qual o código é executado, que tem acesso para criar sandboxes.
Ela será referida como <SANDBOX_CALLER>. A segunda conta é a conta sob a
qual o sandbox é executado. Esta é tipicamente a conta sandbox.
Esta biblioteca atualmente é testada para funcionar com as seguintes versões
Python:
Ubuntu:
(Observe que a versão do Python usada dentro do sandbox pode ser diferente da versão usada para a própria biblioteca.)
Estas instruções detalham como configurar seu sistema operacional para que o
CodeJail possa executar código Python com segurança. No entanto, também é
possível definir codejail.safe_exec.ALWAYS_BE_UNSAFE = True e executar o
Python enviado diretamente na máquina, sem nenhuma segurança. Isso pode ser
aceitável para máquinas de desenvolvedores que não se preocupam com segurança e
permite testar uma integração com a API do CodeJail. No entanto, não deve ser
usado se qualquer entrada vier de fontes não confiáveis. Não use esta opção
em sistemas de produção.
Para garantir a execução segura do Python, você criará um novo virtualenv. Isso significa que você terá dois: o virtualenv principal do seu projeto e o novo para o código Python em sandbox.
Escolha um local para o novo virtualenv e chame-o de . Ele será
detectado e usado automaticamente se você o colocar bem ao lado do seu
virtualenv existente, mas com -sandbox acrescentado. Então, se o seu
virtualenv existente estiver em /home/chris/ve/myproj, faça
ser /home/chris/ve/myproj-sandbox.
O usuário que executa o LMS é <SANDBOX_CALLER>, por exemplo, você na sua
máquina de desenvolvimento, ou www-data em um servidor.
Outros detalhes aqui que dependem da sua configuração:
Crie o novo virtualenv, usando --copies para que haja um executável
Python distinto para limitar::
$ sudo python3.12 -m venv --copies
Por padrão, o virtualenv apenas criaria um symlink para o Python do sistema, e a configuração padrão do apparmor em alguns sistemas operacionais pode impedir que o confinamento seja aplicado a ele.
(Opcional) Se você tiver pacotes específicos que deseja disponibilizar para o seu código em sandbox, instale-os ativando o virtual env do sandbox e usando o pip para instalá-los::
$ /bin/pip install -r requirements/sandbox.txt
Adicione um usuário de sandbox::
$ sudo addgroup sandbox $ sudo adduser --disabled-login sandbox --ingroup sandbox
Permita que o servidor web execute o Python em sandbox como o usuário
sandbox. Crie o arquivo /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
(Observe que o binário find pode executar código arbitrário, portanto
este não é um arquivo sudoers seguro para fins não relacionados ao codejail.)
Edite um perfil do AppArmor. Este é um arquivo de texto que especifica os
limites do executável Python em sandbox. O arquivo deve estar em
/etc/apparmor.d e deve ser nomeado com base no executável, com as barras
substituídas por pontos. Por exemplo, se o seu Python em sandbox estiver em
/home/chris/ve/myproj-sandbox/bin/python, então o seu perfil do AppArmor
deve ser /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python.
Veja o perfil de exemplo em apparmor-profiles/. O perfil deve ser
personalizado para corresponder ao local do seu sandbox.
Analise os perfis::
$ sudo apparmor_parser --replace --warn=all --warn=no-debug-cache --Werror <APPARMOR_FILE>
Reative novamente o virtualenv principal do seu projeto.
Desative o uso do PAM para definir rlimits::
sed -i '/pam_limits.so/d' /etc/pam.d/sudo
Se o seu CodeJail estiver configurado corretamente para usar safe_exec, tente estes comandos no seu terminal 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
Isso deve falhar com uma exceção.
Se você precisar alterar os pacotes instalados no virtualenv do seu sandbox, será necessário desabilitar o AppArmor, porque o seu Python em sandbox não tem os direitos de modificar os arquivos no diretório site-packages.
Desabilite o AppArmor para o seu 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
Instale ou altere os pacotes instalados::
$ pip install -r requirements/sandbox.txt
Reabilite o AppArmor para o seu sandbox::
$ sudo aa-enforce /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Para executar os testes, você deve realizar as etapas de instalação padrão. Em seguida, você deve definir as seguintes variáveis de ambiente::
$ export CODEJAIL_TEST_USER=<owner of sandbox (usually 'sandbox')>
$ export CODEJAIL_TEST_VENV=<SANDENV>
Execute os testes com o Makefile::
$ make tests
Vários testes de proxy são ignorados se o modo proxy não estiver configurado.
O CodeJail é suficientemente versátil para ser usado em uma variedade de projetos para executar código não confiável. Ele fornece duas camadas:
jail_code.py oferece execução segura de subprocessos. Ele faz isso
executando o programa em um subprocesso gerenciado pelo AppArmor.
safe_exec.py oferece tratamento especializado para execução de Python,
usando jail_code para fornecer a semântica da instrução exec do Python.
O CodeJail executa programas sob o AppArmor. O AppArmor é um recurso fornecido pelo sistema operacional para limitar os recursos que os programas podem acessar. Para executar código Python com acesso limitado a recursos, criamos um novo virtualenv, nomeamos esse executável Python em um perfil do AppArmor e restringimos recursos nesse perfil. O CodeJail executará o programa Python fornecido com esse executável, e o AppArmor limitará automaticamente os recursos que ele pode acessar. O CodeJail também usa setrlimit para limitar a quantidade de tempo de CPU e/ou memória disponível ao processo.
codejail.jail_code recebe um programa para executar, arquivos para copiar
para o seu ambiente, argumentos de linha de comando e um fluxo de stdin. Ele
cria um diretório temporário, cria ou copia os arquivos necessários, inicia um
subprocesso para executar o código e retorna a saída e o status de saída do
processo.
codejail.safe_exec emula a instrução exec do Python. Ele recebe um trecho
de código Python e o executa usando jail_code, modificando o dicionário de
globais como efeito colateral. O safe_exec faz isso serializando os globais
para dentro e para fora do subprocesso como JSON.
Se o codejail ou o AppArmor não estiver configurado corretamente, o codejail pode, por padrão, executar código de forma insegura (sem sandbox). Ele não é seguro por padrão. Projetos que integram o codejail devem considerar incluir uma suíte de testes em tempo de execução que verifique o confinamento adequado na inicialização antes que entradas não confiáveis sejam aceitas.
O isolamento do sandbox é alcançado por meio do confinamento do AppArmor. O Codejail facilita isso, mas não pode isolar a execução sem o uso do AppArmor.
Os limites de recursos só podem ser restringidos usando os mecanismos que o rlimit do Linux disponibiliza. Algumas deficiências notáveis:
FSIZE do rlimit possa limitar o tamanho de qualquer arquivo
individual que um processo possa criar e possa limitar o número de arquivos
abertos de cada vez, ele não pode limitar o número total de arquivos
gravados e, portanto, não pode limitar o número total de bytes gravados em
todos os arquivos. Uma mitigação parcial é restringir o tempo máximo de
execução. (Todos os arquivos gravados no sandbox serão excluídos ao final
da execução, de qualquer forma.)NPROC restringe a capacidade do processo atual de criar
novas threads e processos, mas a contagem de uso (quantos processos já
existem) é a soma entre todos os processos com o mesmo UID, mesmo em
outros contêineres no mesmo host onde o UID pode ser mapeado para um nome
de usuário diferente. Essa restrição também se aplica ao usuário do
aplicativo devido à forma como os rlimits são aplicados. Mesmo que UIDs
sejam escolhidos de modo que não sejam usados por outros softwares no host,
múltiplos processos de sandbox do codejail no mesmo host compartilharão
esse pool de uso e podem reduzir a capacidade uns dos outros de criar
processos. Nessa situação, NPROC precisará ser definido com um valor
maior do que seria para uma única instância do codejail processando uma
única solicitação por vez.Sandboxes não têm isolamento forte entre si. Sob configuração adequada, o código não confiável não deve ser capaz de descobrir outras execuções de código em atividade, mas se essa premissa for violada, um sandbox poderia teoricamente interferir em outro.
Por favor, não relate problemas de segurança publicamente. Por favor, envie um e-mail para [email protected].