Premiers pas avec l'API Sandboxed

Sur cette page, vous allez apprendre à créer votre propre bibliothèque C/C++ en bac à sable avec l'API Sandboxed (bac à sable). Utilisez-le comme guide parallèlement aux exemples et à la documentation sur le code dans les fichiers d'en-tête.

Créer des dépendances

Les dépendances suivantes doivent être installées sur le système:

  • Noyau Linux compatible avec les espaces de noms UTS, IPC, user, PID et réseau
  • En-têtes d'API Linux Userspace
  • Pour compiler votre code: GCC 6 (version 7 ou ultérieure de préférence) ou Clang 7 (ou version ultérieure)
  • Pour la génération automatique des fichiers d'en-tête: liaisons Python Clang
  • Python 3.5 ou version ultérieure
  • Bazel version 2.2.0, CMake version 3.12 ou ultérieure
    • CMake uniquement: GNU Make ou une version des en-têtes de bibliothèque libcap et un outil de création tel que Ninja (recommandé)

Utiliser Bazel

Bazel, qui est le système de compilation recommandé, est le plus facile à intégrer.

Notre documentation utilise le compilateur Clang. Si vous avez besoin d'une chaîne d'outils spécifique (compilateur, éditeur de liens, etc.), consultez la documentation Bazel pour savoir comment modifier la chaîne d'outils de compilation par défaut.

Debian 10 (Buster)

Pour installer des dépendances de compilation:

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

Options de noyau requises:

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

Pour installer des dépendances de compilation:

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

Utiliser CMake

CMake est un système de méta-build Open Source courant qui génère des fichiers de projet pour des outils de compilation tels que Ninja ou Make.

Debian 10 (Buster)

Pour installer des dépendances de compilation:

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

Options de noyau requises:

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

Pour installer des dépendances de compilation:

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

Processus de développement

Pour utiliser une bibliothèque C/C++ en bac à sable, vous devez préparer deux éléments pour votre projet:

Vous connaissez peut-être le zlib utilisé dans les exemples Sandbox2. Ici, un programme entier (zpipe.c) a été exécuté en bac à sable. Dans les étapes suivantes, vous allez apprendre à utiliser SAPI pour créer un bac à sable pour la bibliothèque zlib et à utiliser la bibliothèque en bac à sable.

1. Déterminer les fonctions nécessaires

Si vous examinez le code hôte zlib (main_zlib.cc), vous pouvez constater que la fonctionnalité de l'outil consiste à lire les données de stdin et à utiliser la fonction deflate() de zlib pour compresser les données jusqu'à ce qu'un repère EOF soit lu. Au total, le programme utilise trois fonctions de zlib:

  • deflateInit_(): initialiser en vue de la compression.
  • deflate(): pour effectuer l'opération de compression sur le fragment de données
  • deflateEnd(): pour mettre fin à la compression et libérer les structures de données allouées de manière dynamique

Dans un exemple réel, vous examineriez la bibliothèque C/C++ et décideriez quelles fonctions sont nécessaires. Une stratégie possible consiste à commencer avec le code hôte et à utiliser la bibliothèque hors bac à sable. Ensuite, vous pouvez générer la bibliothèque en bac à sable et adapter le code hôte pour utiliser les appels de fonction en bac à sable.

2. Écrire la règle de compilation sapi_library

Après avoir identifié les trois fonctions zlib nécessaires dans la bibliothèque zlib en bac à sable, vous pouvez définir la règle de compilation dans le fichier BUILD. La documentation sur la règle de compilation sapi_library est disponible sur la page Build Rules (Créer des règles).

L'extrait de code ci-dessous montre la définition sapi_library pour l'exemple SAPI zlib. À l'aide de l'attribut lib, Bazel est invité à rechercher la bibliothèque zlib dans le fichier WORKSPACE.

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

Résultat : la bibliothèque zlib en bac à sable est générée. La sortie est l'objet SAPI qui peut être inclus dans le code hôte et utilisé pour communiquer avec la bibliothèque en bac à sable via des appels RPC. La règle de bac à sable utilisée dans cet exemple est la règle par défaut.

3. Écrire ou modifier le code de l'hôte

Il est maintenant temps d'intégrer la bibliothèque SAPI générée dans le code hôte.

Créer le bac à sable

Utilisez sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); pour créer un objet sandbox.

Utilisez sapi::zlib::ZlibApi api(&sandbox); pour instancier l'objet SAPI et rendre ainsi disponibles les fonctions en bac à sable.

Utiliser des types SAPI

Les types SAPI sont des types spéciaux sous la forme de classes C++ fournies par SAPI, car il arrive que les types C standards ne fonctionnent pas.

La première utilisation d'un type SAPI peut être observée dans la déclaration de strm, où un Struct SAPI est utilisé: sapi::v::Struct<sapi::zlib::z_stream> strm;

Le type de modèle (sapi::zlib::z_stream) est un bon exemple de code généré automatiquement par la règle de compilation.

Pour en savoir plus, consultez la page Variables.

Effectuer des appels d'API

Pour appeler defalteInit_, deflate ou deflateEnd, utilisez l'objet SAPI. Si vous décidez d'utiliser l'approche de "modification", vous devez vous assurer que les paramètres de la fonction correspondent aux valeurs attendues.

Voici un exemple de chacun des appels dans l'exemple 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();

Utiliser des transactions SAPI

SAPI isole le code hôte de la bibliothèque de bac à sable et donne à l'appelant la possibilité de redémarrer ou d'abandonner les requêtes de traitement de données problématiques. La transaction SAPI va encore plus loin et répète automatiquement les processus ayant échoué.

Pour en savoir plus, consultez la page Transactions SAPI.

Exemples

Sous Exemples, vous trouverez quelques bibliothèques déjà préparées par l'équipe SAPI.