Erste Schritte mit Sandboxed API

Auf dieser Seite erfahren Sie, wie Sie mit der Sandboxed API (SAPI) Ihre eigene C/C++-Bibliothek erstellen, die in einer Sandbox ausgeführt wird. Verwenden Sie es zusammen mit den Beispielen und der Code-Dokumentation in den Header-Dateien als Leitfaden.

Abhängigkeiten erstellen

Die folgenden Abhängigkeiten müssen auf dem System installiert sein:

  • Linux-Kernel mit Unterstützung für UTS-, IPC-, Nutzer-, PID- und Netzwerk-Namespaces
  • Linux Userspace API-Header
  • So kompilieren Sie Ihren Code: GCC 6 (ab Version 7) oder Clang 7 (oder höher)
  • Für das automatische Generieren von Header-Dateien: Clang-Python-Bindungen
  • Python 3.5 oder höher
  • Bazel Version 2.2.0 oder CMake Version 3.12 oder höher.
    • Nur CMake: GNU Make oder eine Version der Header der libcap-Bibliothek und ein Build-Tool wie Ninja (empfohlen).

Bazel verwenden

Das empfohlene Build-System ist am einfachsten zu integrieren.

Unsere Dokumentation verwendet den Clang-Compiler. Wenn Sie eine bestimmte Toolchain benötigen (z.B. Compiler, Verknüpfung usw.), finden Sie in der Bazel-Dokumentation Informationen zum Ändern der Standard-Compiler-Toolchain.

Debian 10 (Buster)

So installieren Sie Build-Abhängigkeiten:

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

Eselspinguine

Erforderliche Kerneloptionen:

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

So installieren Sie Build-Abhängigkeiten:

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

CMake verwenden

CMake ist ein beliebtes Open-Source-Meta-Build-System, mit dem Projektdateien für Build-Tools wie Ninja oder Make generiert werden.

Debian 10 (Buster)

So installieren Sie Build-Abhängigkeiten:

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

Eselspinguine

Erforderliche Kerneloptionen:

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

So installieren Sie Build-Abhängigkeiten:

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

Entwicklungsprozess

Um eine C/C++-Bibliothek in einer Sandbox auszuführen, müssen Sie zwei Elemente für Ihr Projekt vorbereiten:

Vielleicht sind Sie mit den zlib-Beispielen aus den Sandbox2-Beispielen vertraut. Hier wurde ein ganzes Programm (zpipe.c) in einer Sandbox ausgeführt. In den folgenden Schritten erfahren Sie, wie Sie SAPI verwenden, um die zlib-Bibliothek in einer Sandbox zu verarbeiten und die Sandbox-Bibliothek zu nutzen.

1. Entscheiden, welche Funktionen benötigt werden

Wenn Sie sich den zlib-Hostcode (main_zlib.cc) ansehen, stellen Sie fest, dass das Tool Daten aus stdin liest und die Funktion deflate() von zlib verwendet, um die Daten zu komprimieren, bis eine EOF-Markierung gelesen wird. Insgesamt verwendet das Programm drei Funktionen von zlib:

  • deflateInit_(): zum Initialisieren der Komprimierung
  • deflate(): zum Ausführen der Komprimierung für den Datenblock
  • deflateEnd(): zum Beenden der Komprimierung und zum Freigeben dynamisch zugewiesener Datenstrukturen

In einem realen Beispiel würden Sie sich die C/C++-Bibliothek ansehen und entscheiden, welche Funktionen benötigt werden. Eine mögliche Strategie besteht darin, mit dem Hostcode zu beginnen und die Bibliothek ohne Sandbox zu verwenden. Im zweiten Schritt könnten Sie dann die Sandbox-Bibliothek generieren und den Hostcode so anpassen, dass die in der Sandbox ausgeführten Funktionsaufrufe verwendet werden.

2. Build-Regel sapi_library schreiben

Nachdem Sie die drei erforderlichen zlib-Funktionen in der zlib-Bibliothek identifiziert haben, die in einer Sandbox ausgeführt werden, können Sie die Build-Regel in der Datei build definieren. Die Dokumentation für die Build-Regel sapi_library finden Sie auf der Seite Build-Regeln.

Das folgende Code-Snippet zeigt die sapi_library-Definition für das zlib SAPI-Beispiel. Mithilfe des Attributs lib wird Bazel angewiesen, in der Datei WORKSPACE nach der zlib-Bibliothek zu suchen.

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

Das Ergebnis ist, dass die in einer Sandbox ausgeführte zlib-Bibliothek generiert wird. Die Ausgabe ist das SAPI-Objekt, das in den Hostcode aufgenommen und für die Kommunikation mit der in der Sandbox ausgeführten Bibliothek über RPC-Aufrufe verwendet werden kann. Die in diesem Beispiel verwendete Sandbox-Richtlinie ist die Standardrichtlinie.

3. Hostcode schreiben oder ändern

Jetzt ist es an der Zeit, die generierte SAPI-Bibliothek in den Hostcode zu integrieren.

Sandbox erstellen

Verwenden Sie sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create());, um ein Sandbox-Objekt zu erstellen.

Verwenden Sie sapi::zlib::ZlibApi api(&sandbox);, um das SAPI-Objekt zu instanziieren und die Sandbox-Funktionen zur Nutzung verfügbar zu machen.

SAPI-Typen verwenden

SAPI-Typen sind spezielle Typen in Form von C++-Klassen, die von SAPI bereitgestellt werden, da reguläre C-Typen manchmal nicht funktionieren.

Die erste Verwendung eines SAPI-Typs ist in der Deklaration von strm zu beobachten, wobei eine SAPI-Struktur verwendet wird: sapi::v::Struct<sapi::zlib::z_stream> strm;

Der Vorlagentyp (sapi::zlib::z_stream) ist ein gutes Beispiel für Code, der automatisch von der Build-Regel generiert wird.

Weitere Informationen finden Sie auf der Seite Variablen.

API-Aufrufe ausführen

Verwenden Sie das SAPI-Objekt, um defalteInit_, deflate oder deflateEnd aufzurufen. Wenn Sie sich für den Ansatz „change“ (Ändern) entscheiden, müssen Sie darauf achten, dass die Funktionsparameter den erwarteten Werten entsprechen.

Beispiel für die einzelnen Aufrufe im zlib-Beispiel:

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

SAPI-Transaktionen verwenden

SAPI isoliert den Hostcode von der Sandboxed Library und gibt dem Aufrufer die Möglichkeit, problematische Datenverarbeitungsanfragen neu zu starten oder abzubrechen. Die SAPI-Transaktion geht noch einen Schritt weiter und wiederholt fehlgeschlagene Prozesse automatisch.

Weitere Informationen finden Sie auf der Seite für SAPI-Transaktionen.

Beispiele

Unter Beispiele finden Sie einige Bibliotheken, die bereits vom SAPI-Team erstellt wurden.