Executar um programa C não confiável em uma sandbox no Linux que o impede de abrir arquivos, bifurcação, etc.?

110

Eu queria saber se existe uma maneira de executar um programa C não confiável em uma área restrita no Linux. Algo que impediria o programa de abrir arquivos ou conexões de rede, bifurcação, exec, etc?

Seria um pequeno programa, uma tarefa de casa, que é carregada em um servidor e tem testes de unidade executados nele. Portanto, o programa teria vida curta.

Frank
fonte
É como um único programa em C que você precisa para executar uma vez por 5 minutos ou algo que você precisa executar constantemente?
bwawok
Seria um pequeno programa que é carregado e tem testes de unidade executados nele. Portanto, o programa teria vida curta.
Frank
Qual distribuição o sistema está usando? Algumas distribuições têm ferramentas prontas para sandbox. Seu sistema tem algum modelo de segurança como SELinux ou AppArmor habilitado?
thkala de
Estou usando o Fedora 13. Estou examinando a política do SELinux Sandbox. Estou me perguntando quais outras opções existem.
Frank
6
Perguntas semelhantes sobre processos de sandbox / jailing no Linux ou Unix: * unix.stackexchange.com/q/6433/4319 * stackoverflow.com/q/3859710/94687 * stackoverflow.com/q/4410447/94687 * stackoverflow.com/q / 1019707/94687
imz - Ivan Zakharyaschev

Respostas:

47

Eu usei o Systrace para colocar programas não confiáveis ​​na sandbox tanto interativamente quanto no modo automático. Ele tem um ptrace()backend baseado em que permite seu uso em um sistema Linux sem privilégios especiais, bem como um backend muito mais rápido e poderoso que requer patch do kernel.

Também é possível criar uma sandbox em sistemas do tipo Unix usando chroot(1), embora isso não seja tão fácil ou seguro. Os contêineres do Linux e as jaulas do FreeBSD são uma alternativa melhor ao chroot. Outra alternativa no Linux é usar um framework de segurança como SELinux ou AppArmor , que é o que eu proporia para sistemas de produção.

Seríamos capazes de ajudá-lo mais se você dissesse exatamente o que é que você deseja fazer.

EDITAR:

Systrace funcionaria para o seu caso, mas acho que algo baseado no modelo de segurança do Linux, como AppArmor ou SELinux, é uma alternativa mais padrão e, portanto, preferencial, dependendo da sua distribuição.

EDIT 2:

Embora chroot(1)esteja disponível na maioria (todos?) Dos sistemas do tipo Unix, tem alguns problemas:

  • Ele pode ser quebrado. Se você for realmente compilar ou executar programas C não confiáveis ​​em seu sistema, estará especialmente vulnerável a esse problema. E se seus alunos forem parecidos com os meus, alguém VAI tentar escapar da prisão.

  • Você deve criar uma hierarquia de sistema de arquivos totalmente independente com tudo o que é necessário para sua tarefa. Você não precisa ter um compilador no chroot, mas tudo o que é necessário para executar os programas compilados deve ser incluído. Embora existam utilitários que ajudam com isso, ainda não é trivial.

  • Você tem que manter o chroot. Por ser independente, os arquivos chroot não serão atualizados junto com sua distribuição. Você terá que recriar o chroot regularmente ou incluir as ferramentas de atualização necessárias nele, o que essencialmente requer que seja uma distribuição Linux completa. Você também terá que manter os dados do sistema e do usuário (senhas, arquivos de entrada, etc.) sincronizados com o sistema host.

  • chroot()protege apenas o sistema de arquivos. Não impede que um programa malicioso abra sockets de rede ou um programa mal escrito de sugar todos os recursos disponíveis.

O problema de uso de recursos é comum entre todas as alternativas. As cotas do sistema de arquivos impedirão que os programas ocupem o disco. As configurações adequadas ulimit( setrlimit()em C) podem proteger contra o uso excessivo de memória e quaisquer bombas de fork, bem como acabar com os devoradores de CPU. nice(1)pode diminuir a prioridade desses programas para que o computador possa ser usado para quaisquer tarefas consideradas mais importantes sem problemas.

thkala
fonte
systrace funcionou para mim para programas simples, mas ficou preso indefinidamente quando o GNU as (1) era executado pelo GCC. Então desisti. É um bug não corrigido no systrace: forum.soft32.com/linux/…
pts
Existe uma maneira de garantir que a memória compartilhada, filas de mensagens e semáforos não sejam compartilhados entre processos em área restrita?
daveagp
1
O link do systrace está quebrado.
Collin
2
E quanto ao Firejail? Você não precisa mais manter o fs usando-o.
m3nda
18

Recentemente, escrevi uma visão geral das técnicas de sandboxing no Linux . Acho que sua abordagem mais fácil seria usar contêineres Linux (lxc) se você não se importasse com bifurcação e assim por diante, o que realmente não importa neste ambiente. Você pode dar ao processo um sistema de arquivos raiz somente leitura, uma conexão de rede de loopback isolada e ainda pode eliminá-lo facilmente e definir limites de memória, etc.

Seccomp vai ser um pouco difícil, já que o código nem consegue alocar memória.

Selinux é a outra opção, mas acho que pode dar mais trabalho do que um container.

Justin Cormack
fonte
6

Você pode usar o Qemu para testar atribuições rapidamente. O procedimento abaixo leva menos de 5 segundos no meu laptop de 5 anos.

Vamos supor que o aluno tenha que desenvolver um programa que aceite ints sem sinal, cada um em sua própria linha, até que uma linha com "-1" chegue. O programa deve então calcular a média de todos os ints e saída "Média:% f". Veja como você pode testar o programa completamente isolado:

  1. Primeiro, pegue o root.binJslinux, vamos usar isso como a área de usuário (tem o compilador C tcc):

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

  2. Queremos colocar o envio do aluno root.bin, então configure o dispositivo de loop:

    sudo losetup /dev/loop0 root.bin

    (você poderia usar fuseext2 para isso também, mas não é muito estável. Se estabilizar, você não precisará do root para nada disso)

  3. Faça um diretório vazio:

    mkdir mountpoint

  4. Monte root.bin:

    sudo mount /dev/loop0 mountpoint

  5. Digite o sistema de arquivos montado:

    cd mountpoint.

  6. Direitos de correção:

    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. Copie o envio para a VM:

    cp ~/student_assignment.c root/assignment.c

  11. Saia do FS raiz da VM:

    cd ..

  12. sudo umount mountpoint
  13. Agora a imagem está pronta, só precisamos executá-la. Ele irá compilar e executar o envio após a inicialização.
  14. mkfifo /tmp/guest_output
  15. Abra um terminal separado e comece a ouvir a saída do convidado:

    dd if=/tmp/guest_output bs=1

  16. Em outro terminal:

    qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput (Acabei de usar o kernel do Ubuntu aqui, mas muitos kernels funcionarão)

  17. Quando a saída do convidado mostra "READY", você pode enviar chaves para a VM a partir do prompt do qemu. Por exemplo, para testar esta tarefa, você poderia fazer

    (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. Agora Average = 12.000000deve aparecer no tubo de saída do convidado. Se não, o aluno falhou.

  19. Saia do qemu: quit

Um programa que passou no teste está aqui: https://stackoverflow.com/a/14424295/309483 . Basta usar em tcclib.hvez de stdio.h.

Janus Troelsen
fonte
5

Experimente o Linux no modo de usuário . Ele tem cerca de 1% de sobrecarga de desempenho para trabalhos com uso intensivo de CPU, mas pode ser 6 vezes mais lento para trabalhos com uso intenso de E / S.

pts
fonte
4

Firejail é uma das ferramentas mais abrangentes para fazer isso - suporta seccomp, contêineres de sistema de arquivos, recursos e muito mais:

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

Federico
fonte
Esta resposta é excelente, realmente merece mais votos positivos, considerando que o firejail é mantido ativamente com boa documentação, abrange a maioria, senão todas as outras respostas e é projetado para ser relativamente fácil de usar.
Jeff Hykin
3

Executá-lo dentro de uma máquina virtual deve oferecer a você toda a segurança e restrições que você deseja.

O QEMU seria uma boa opção para isso e todo o trabalho (baixar o aplicativo, atualizar a imagem do disco, iniciar o QEMU, executar o aplicativo dentro dele e salvar a saída para recuperação posterior) poderia ser criado para testes automatizados.

Laurent Parenteau
fonte
2
Não sei sobre o OP, mas lançar uma VM por programa de teste seria inaceitável em muitos casos. No meu ambiente (sou um TA), pode haver até 200 alunos submetendo 10-12 programas cada em um período de 2 horas. Nenhum programa é executado por mais de 10 segundos de tempo de CPU, mas quando os envios se acumulam, obtemos tempos de resposta de 15 minutos ou mais. A introdução de uma VM para cada programa aumentaria o tempo de CPU para 60 segundos ou mais por programa e não quero pensar sobre os tempos de retorno. Talvez uma VM por sessão, mas não poderíamos fazer isso por programa ...
thkala
@thkala Este é um bom ponto. Gosto da ideia do QEMU, mas iniciar uma VM para cada envio não é bom.
Frank
Bem, nesse caso, mantenha a mesma VM em execução o tempo todo.
Laurent Parenteau
Você poderia fazer algo usando um instantâneo de uma VM que está totalmente inicializada e pronta para compilar e executar o código? Para sua informação, as VMs não são necessariamente imunes a piercings. Você também pode construir uma versão de hardware disso - um pequeno sistema que inicializa uma imagem de currículo de uma mídia somente leitura ou pela rede e fornece saída via rede ou serial e, em seguida, é reiniciado para a próxima. Houve alguns avanços rápidos na inicialização que colocam o Linux no ar em alguns segundos.
Chris Stratton
@thkala: Isso significa que você precisaria de menos de 3 segundos por envio se os executasse em série. A abordagem que postei provavelmente leva cerca de 3 segundos em uma máquina moderna (em série). Se você paralelizar (o que também pode acontecer), será rápido o suficiente.
Janus Troelsen
3

Quando se trata de sanboxing com base no check-out de ptrace (strace):

" sydbox " sandbox e biblioteca de programação " pinktrace " (é C99, mas existem ligações para python e ruby ​​até onde eu sei).

Links coletados relacionados ao tópico:

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

(desculpe, não links diretos, mas ainda não há pontos de reputação suficientes)

Grzegorz Wierzowiecki
fonte
1

Esta biblioteca deve servir bem ao seu objetivo

http://sandbox.sourceforge.net

Boa sorte!

thoaionline
fonte
8
Isso não parece ser mantido ativamente. Ele também parece exigir um patch do kernel do Linux, o que o tornaria praticamente inútil, considerando que sua versão mais recente remonta a 2003.
thkala
1

Isso também parece promissor. Uma caixa de areia do sistema de arquivos para Linux usando interceptações syscall.

https://github.com/adtac/fssb

mauron85
fonte
-1

ok graças a todas as respostas eles me ajudaram muito. Mas eu não sugeriria nenhum deles como solução para a pessoa que fez a pergunta original. Todas as ferramentas mencionadas exigem muito trabalho com o propósito de testar o código dos alunos como professor, tutor, prof. A melhor forma neste caso seria na minha opinião o virtualbox. Ok, isso emula um sistema x68 completo e não tem nada a ver com o significado de sandboxing dessa forma, mas se eu imaginar meu professor de programação, seria o melhor para ele. Então "apt-get install virtualbox" em sistemas baseados em debian, todos os outros vão para http://virtualbox.org/ , crie uma vm, adicione uma iso, clique em instalar, espere um pouco e tenha sorte. Será muito mais fácil de usar para configurar o modo de usuário-linux ou fazer alguma coisa pesada ...

E se você tem medo de seus alunos hackearem você, eu acho que você tem um problema de autoridade e uma solução para isso seria ameaçá-los de que você os processará até a morte se puder provar apenas uma mordida de maleware no trabalho que eles dão vocês...

Além disso, se houver uma classe e 1% dela for tão boa quanto ele poderia fazer essas coisas, não os entedie com tarefas tão simples e dê a eles algumas grandes onde eles tenham que codificar um pouco mais. A aprendizagem integrativa é melhor para todos, então não confie em velhas estruturas em impasse ...

E, claro, nunca use o mesmo computador para coisas importantes (como redigir atestados e exames), que você está usando para coisas como navegar na web e testar software.

Use um computador off-line para coisas importantes e um computador on-line para todas as outras coisas.

No entanto, para todos os outros que não são professores paranóicos (não quero ofender ninguém, sou apenas a opinião de que você deve aprender o básico sobre segurança e nossa sociedade antes de começar a ser um professor de programadores ...)

... onde eu estava ... para todos os outros:

feliz hackeando !!

rohySeentrusted
fonte