Perguntas frequentes

Posso usar as linhas de execução?

Sim, as linhas de execução são compatíveis com o Sandbox2.

Todas as linhas de execução precisam estar no sandbox

Devido à maneira como o Linux funciona, a política seccomp-bpf é aplicada somente ao thread atual. Isso significa que ela não é aplicada a outros threads existentes, mas os tópicos futuros herdarão a política:

  • Se você estiver usando o Sandbox2 no primeiro modo, em que o sandbox é ativado antes de execve(), todas as linhas de execução vão herdar a política, e não há problemas. Esse é o modo preferencial de sandbox.
  • Se você estiver usando o segundo modo, em que o executor tem set_enable_sandbox_before_exec(false) e o sandboxee informa ao executor quando ele quer ficar no sandbox com SandboxMeHere(), confira se o filtro está aplicado a todas as linhas de execução. Caso contrário, há o risco de escape de sandbox: códigos maliciosos podem migrar de um thread no sandbox para um que não está no sandbox.

Como devo compilar meu sandboxee?

Se você não for cuidadoso, é fácil herdar muitas dependências e efeitos colaterais (chamadas de sistema extras, acessos a arquivos ou até mesmo conexões de rede), que tornam o sandbox mais difícil (rastreamento de todos os efeitos colaterais) e menos seguro (porque as políticas de syscall e arquivo são mais amplas). Algumas opções de compilação podem ajudar a reduzir esses problemas:

  • Compile estaticamente o binário do sandboxee para evitar a vinculação dinâmica, que usa muitas chamadas do sistema (open/openat, mmap etc.).
  • Como o Bazel adiciona pie por padrão, mas a estática é incompatível, use a flag de recursos para forçá-la com as seguintes opções nas regras cc_binary:

    linkstatic = 1,
    features = [
        "fully_static_link",  # link libc statically
        "-pie",
    ],
    

No entanto:o uso de dados estáticos tem a desvantagem de reduzir a entropia de heap ASLR (de 30 bits para 8 bits), facilitando as explorações. Decida cuidadosamente qual é a melhor opção, dependendo da implementação e política do seu sandbox:

  • não estático: bom ASLR de heap, potencialmente mais difícil de executar o código inicial, mas à custa de uma política de sandbox menos eficaz, potencialmente mais fácil de romper.
  • static: ASLR de heap ruim, potencialmente mais fáceis de executar o código inicial, mas com uma política de sandbox mais eficaz, possivelmente mais difícil de sair.

Essa é uma escolha ruim porque o compilador não oferece suporte a executáveis independentes de posição (PIE, na sigla em inglês). Para implementar o PIE, o binário é um objeto dinâmico, e o carregador dinâmico o mapeia em um local aleatório antes de executá-lo. Então, como a pilha é tradicionalmente colocada em um deslocamento aleatório após o endereço base do binário (e expandida com brk syscall), isso significa que, para binários estáticos, a entropia ASLR da pilha é apenas esse deslocamento, porque não há PIE.

Para conferir exemplos dessas opções de compilação, veja o exemplo estático BUILD.bazel: static_bin.cc é compilado estaticamente, o que nos permite ter uma política syscall muito restrita. Isso também funciona bem para colocar binários de terceiros no sandbox.

Posso colocar binários x86 de 32 bits no sandbox?

O sandbox2 só pode colocar no sandbox a mesma arquitetura com que foi compilado.

Além disso, o suporte para x86 de 32 bits foi removido do Sandbox2. Se você tentar usar um executor x86 de 64 bits para colocar um binário x86 de 32 bits no sandbox ou um binário x86 de 64 bits que cria syscalls de 32 bits (via int 0x80), ambos vão gerar uma violação de sandbox que pode ser identificada pelo rótulo de arquitetura [X86-32].

O motivo por trás desse comportamento é que os números do syscall são diferentes entre as arquiteturas. Como a política do syscall é escrita na arquitetura do executor, seria perigoso permitir uma arquitetura diferente para o sandboxee. Na verdade, isso pode levar a um sistema aparentemente inofensivo que, na verdade, significa que outro sistema mais prejudicial poderia abrir o sandbox para uma fuga.

Há algum limite para o número de sandboxes que um processo de executor pode solicitar?

Para cada instância do Sandboxee (novo processo gerado pelo servidor de bifurcação), uma nova linha de execução é criada. É aí que está a limitação.

Um executor pode solicitar a criação de mais de um sandbox?

Não. Existe uma relação 1:1: uma instância do Executor armazena o PID do sandboxee, gerencia a instância Comms à instância do sandbox etc.

Por que vejo "Função não implementada" dentro de forkserver.cc?

O sandbox2 só oferece suporte à execução em kernels razoavelmente novos. Nosso limite atual é o kernel 3.19, embora isso possa mudar no futuro. O motivo é que estamos usando recursos relativamente novos do kernel, incluindo namespaces de usuários e seccomp com a sinalização TSYNC.

Se você estiver executando em produção, isso não deve ser um problema, já que quase toda a frota está executando um kernel novo o suficiente. Se você tiver algum problema, entre em contato com nossa equipe.

Se você estiver executando no Debian ou no Ubuntu, atualizar o kernel será tão fácil quanto executar:

sudo apt-get install linux-image-<RECENT_VERSION>