Comienza a usar la API de Sandboxed

En esta página, aprenderás a crear tu propia biblioteca de C/C++ en zona de pruebas con la API de Sandboxed (SAPI). Úsala como guía junto con los ejemplos y la documentación del código en los archivos de encabezado.

Dependencias de la compilación

Se deben instalar las siguientes dependencias en el sistema:

  • Kernel de Linux con compatibilidad para UTS, IPC, usuario, PID y espacios de nombres de red
  • Encabezados de la API del espacio de usuario de Linux
  • Para compilar tu código: GCC 6 (se prefiere la versión 7 o posterior) o Clang 7 (o posterior)
  • Para generar de forma automática archivos de encabezado: vinculaciones de Python de Clang
  • Python 3.5 o versiones posteriores
  • Bazel versión 2.2.0 o CMake versión 3.12 o versiones posteriores
    • Solo CMake: GNU Make o una versión de los encabezados de la biblioteca libcap y una herramienta de compilación como Ninja (recomendado)

Usa Bazel

Bazel es el sistema de compilación recomendado y el más fácil de integrar.

Nuestra documentación usa el compilador Clang. Si necesitas una cadena de herramientas específica (p.ej., compilador, vinculador, etc.), consulta la documentación de Bazel para obtener información sobre cómo cambiar la cadena de herramientas del compilador predeterminada.

Debian 10 (Buster)

Para instalar dependencias de compilación, haz lo siguiente:

echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://releases.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

Opciones de kernel requeridas:

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

Para instalar dependencias de compilación, haz lo siguiente:

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

Usa CMake

CMake es un sistema de metacomilación popular de código abierto que genera archivos de proyecto para herramientas de compilación como Ninja o Make.

Debian 10 (Buster)

Para instalar dependencias de compilación, haz lo siguiente:

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

Opciones de kernel requeridas:

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

Para instalar dependencias de compilación, haz lo siguiente:

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

Proceso de desarrollo

Para crear una biblioteca de C/C++ en zona de pruebas, deberás preparar dos elementos para tu proyecto:

Es posible que conozcas zlib de los ejemplos de Sandbox2. Aquí se creó una zona de pruebas para un programa completo (zpipe.c) . En los siguientes pasos, aprenderás a usar SAPI para crear una zona de pruebas para la biblioteca zlib y usar la biblioteca en zona de pruebas.

1. Decide qué funciones son necesarias

Si observas el código de host de zlib (main_zlib.cc), puedes ver que la funcionalidad de la herramienta es leer datos de stdin y usar la función deflate() de zlib para comprimir los datos hasta que se lea un marcador EOF. En total, el programa usa tres funciones de zlib:

  • deflateInit_(): Para inicializar la compresión
  • deflate(): Para realizar la operación de compresión en el fragmento de datos
  • deflateEnd(): Para finalizar la compresión y liberar las estructuras de datos asignadas de forma dinámica

En un ejemplo de la vida real, revisarías la biblioteca de C/C++ y decidirías qué funciones son necesarias. Una estrategia posible es comenzar con el código de host y usar la biblioteca sin zona de pruebas. Luego, en un segundo paso, podrías generar la biblioteca en zona de pruebas y adaptar el código de host para usar las llamadas a funciones en zona de pruebas.

2. Escribe la regla de compilación sapi_library

Después de identificar las tres funciones de zlib que se necesitan de la biblioteca de zlib en zona de pruebas, puedes definir la regla de compilación en el archivo BUILD. La documentación de la regla de compilación sapi_library se puede encontrar en la página Reglas de compilación.

En el siguiente fragmento de código, se muestra la definición de sapi_library para el ejemplo de SAPI de zlib. Con el atributo lib, se le indica a Bazel que busque la biblioteca zlib en el archivo WORKSPACE.

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

Como resultado, se genera la biblioteca de zlib en zona de pruebas. El resultado es el objeto SAPI que se puede incluir en el código de host y se puede usar para comunicarse con la biblioteca en zona de pruebas mediante llamadas a RPC.

En este ejemplo, se usa la configuración predeterminada de la zona de pruebas que proporciona DefaultConfig (sapi::SandboxConfig::DefaultConfig()).

3. Escribe o cambia el código de host

Ahora es el momento de incorporar la biblioteca SAPI generada en el código de host.

Crea la zona de pruebas

Usa sapi::zlib::ZlibSandbox sandbox; para crear un objeto de zona de pruebas.

Usa sapi::zlib::ZlibApi api(&sandbox); para crear una instancia del objeto SAPI y, de esta manera, hacer que las funciones en zona de pruebas estén disponibles para su uso.

Para personalizar la política, las marcas, las variables de entorno o los límites de la zona de pruebas, comienza con sapi::SandboxConfig::DefaultConfig(), modifica los campos relevantes (con sapi::Sandbox2Config::DefaultPolicyBuilder(), sapi::SandboxConfig::DefaultFlags(), o sapi::SandboxConfig::DefaultEnvironmentVariables() para que se conserven los parámetros de configuración de referencia) y pasa el sapi::SandboxConfig al constructor de la zona de pruebas:

sapi::SandboxConfig config = sapi::SandboxConfig::DefaultConfig();
config.sandbox2.policy = sapi::Sandbox2Config::DefaultPolicyBuilder()
                             .AddFile("/path/to/file")
                             .BuildOrDie();
auto flags = sapi::SandboxConfig::DefaultFlags();
flags["my_flag"] = "value";
config.command_line_flags = std::move(flags);

sapi::zlib::ZlibSandbox sandbox(std::move(config));

Usa tipos de SAPI

Los tipos de SAPI son tipos especiales en forma de clases de C++ que proporciona SAPI porque, a veces, los tipos C normales no funcionan.

El primer uso de un tipo de SAPI se puede observar en la declaración de strm, donde se usa una estructura de SAPI: sapi::v::Struct<sapi::zlib::z_stream> strm;

El tipo de plantilla (sapi::zlib::z_stream) es un buen ejemplo de código generado automáticamente por la regla de compilación.

Consulta la página Variables para obtener más detalles.

Realiza llamadas a la API

Para realizar llamadas a defalteInit_, deflate o deflateEnd, usa el objeto SAPI. Si decides usar el enfoque de “cambio”, debes asegurarte de que los parámetros de la función coincidan con los valores esperados.

Un ejemplo de cada una de las llamadas en el ejemplo de zlib:

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

Usa transacciones de SAPI

SAPI aísla el código de host de la biblioteca en zona de pruebas y le da al llamador la capacidad de reiniciar o anular las solicitudes de procesamiento de datos problemáticas. La transacción de SAPI va un paso más allá y repite automáticamente los procesos fallidos.

Consulta la página Transacciones de SAPIpara obtener más detalles.

Ejemplos

En Ejemplos, puedes encontrar algunas bibliotecas, ya preparadas por el equipo de SAPI.