Primeiros passos com a API no modo sandbox

Nesta página, você vai aprender a criar sua própria biblioteca C/C++ no modo sandbox com a API Sandbox (SAPI). Use-o como um guia, junto com os exemplos e a documentação do código nos arquivos principais.

Dependências de build

As seguintes dependências precisam ser instaladas no sistema:

  • Kernel do Linux com suporte a namespaces de UTS, IPC, usuário, PID e rede
  • Cabeçalhos da API Linux userspace
  • Para compilar o código: GCC 6 (preferencialmente versão 7 ou mais recente) ou Clang 7 (ou mais recente).
  • Para geração automática de arquivos de cabeçalho: vinculações do Clang Python
  • Python 3.5 ou posterior
  • Bazel versão 2.2.0 ou CMake versão 3.12 ou mais recente.
    • Somente CMake: GNU Make ou uma versão dos cabeçalhos da biblioteca libcap e uma ferramenta de build, como Ninja (recomendado).

Como usar o Bazel

O Bazel é o sistema de build recomendado e é o mais fácil de integrar.

Nossa documentação usa o compilador do Clang. Se você precisar de um conjunto de ferramentas específico (por exemplo, compilador, vinculador etc.), consulte a documentação do Bazel para ver informações sobre como alterar o conjunto de ferramentas do compilador padrão.

Debian 10 (Buster)

Para instalar dependências de build:

echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install -qy build-essential linux-libc-dev bazel python3 \
  python3-pip libclang-dev
pip3 install clang

Gentoo

Opções do kernel necessárias:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

Para instalar dependências de build:

emerge dev-util/bazel dev-python/typing dev-python/clang-python

Como usar o CMake

O CMake é um sistema conhecido de metabuild de código aberto que gera arquivos de projeto para ferramentas de build, como Ninja ou Make.

Debian 10 (Buster)

Para instalar dependências de build:

sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \
  python3 python3-pip libclang-dev libcap-dev
pip3 install absl-py clang

Gentoo

Opções do kernel necessárias:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

Para instalar dependências de build:

emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-python

Processo de desenvolvimento

Para colocar uma biblioteca C/C++ no sandbox, você precisará preparar dois itens para seu projeto:

Você já deve conhecer o zlib dos exemplos de Sandbox2 (link em inglês) usado aqui: um programa inteiro (zpipe.c) foi colocado no sandbox. Nas etapas a seguir, você vai aprender a usar a SAPI para sandbox a biblioteca zlib e usar a biblioteca no modo sandbox.

1. Decidir quais funções são necessárias

Se você observar o código do host zlib (main_zlib.cc), verá que a funcionalidade da ferramenta é ler dados de stdin e usar a função deflate() do zlib para compactar os dados até que um marcador EOF seja lido. No total, o programa usa três funções do zlib:

  • deflateInit_(): para inicializar para compactação
  • deflate(): executar a operação de compactação no bloco de dados.
  • deflateEnd(): para encerrar a compactação e liberar as estruturas de dados alocadas dinamicamente

Em um exemplo real, você revisaria a biblioteca C/C++ e decidiria quais funções são necessárias. Uma estratégia possível é começar com o código de host e usar a biblioteca fora da sandbox. Em seguida, em uma segunda etapa, você pode gerar a biblioteca no modo sandbox e adaptar o código do host para usar as chamadas de função no sandbox.

2. Escrever a regra de build sapi_library

Depois de identificar as três funções zlib que são necessárias na biblioteca zlib no modo sandbox, você pode definir a regra de compilação no arquivo BUILD. A documentação da regra de build sapi_library pode ser encontrada na página Regras de build.

O snippet de código abaixo mostra a definição sapi_library para o exemplo zlib SAPI. Usando o atributo lib, o Bazel é instruído a procurar a biblioteca zlib no arquivo WORKSPACE.

sapi_library(
    name = "zlib-sapi",
    srcs = [],
    hdrs = [],
    functions = [
        "deflateInit_",
        "deflate",
        "deflateEnd",
    ],
    lib = "@net_zlib//:zlib",
    lib_name = "Zlib",
    namespace = "sapi::zlib",
)

Como resultado, a biblioteca zlib no modo sandbox é gerada. A saída é o objeto SAPI que pode ser incluído no código do host e usado para se comunicar com a biblioteca em sandbox por chamadas RPC. A política de sandbox usada neste exemplo é a política padrão.

3. Escrever ou alterar o código de host

Agora é hora de incorporar a biblioteca SAPI gerada no código de host.

Criar o sandbox

Use sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); para criar um objeto de sandbox.

Use sapi::zlib::ZlibApi api(&sandbox); para instanciar o objeto SAPI e disponibilizar as funções no sandbox para uso.

Usar tipos SAPI

Os tipos SAPI são tipos especiais na forma de classes C++ fornecidas pela SAPI porque, às vezes, os tipos C normais não funcionam.

O primeiro uso de um tipo SAPI pode ser observado na declaração de strm, em que um Struct SAPI é usado: sapi::v::Struct<sapi::zlib::z_stream> strm;

O tipo de modelo (sapi::zlib::z_stream) é um bom exemplo de código gerado automaticamente pela regra de criação.

Confira a página Variáveis para mais detalhes.

Fazer chamadas de API

Para fazer chamadas para defalteInit_, deflate ou deflateEnd, use o objeto SAPI. Se você decidir usar a abordagem de "mudança", precisará garantir que os parâmetros da função correspondam aos valores esperados.

Um exemplo de cada uma das chamadas no exemplo de zlib (link em inglês):

  • api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
        version.PtrBefore(), sizeof(sapi::zlib::z_stream));
  • api.deflate(strm.PtrBoth(), flush);
  • api.deflateEnd(strm.PtrBoth()).IgnoreError();

Como usar transações SAPI

O SAPI isola o código de host da biblioteca em sandbox e permite que o autor da chamada reinicie ou cancele solicitações de processamento de dados problemáticas. A transação SAPI vai além e repete automaticamente os processos com falha.

Confira a página de transações SAPI para mais detalhes.

Exemplos

Em Exemplos, você encontra algumas bibliotecas já preparadas pela equipe de SAPI.