Erste Schritte mit Sandboxed API

Auf dieser Seite erfahren Sie, wie Sie mit Sandboxed API (SAPI) eine eigene Sandbox-C/C++-Bibliothek erstellen. Verwenden Sie es als Leitfaden zusammen mit den Beispielen und der Codedokumentation in den Headerdateien.

Build-Abhängigkeiten

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
  • Zum Kompilieren des Codes: GCC 6 (Version 7 oder höher empfohlen) oder Clang 7 (oder höher)
  • Automatische Generierung von Header-Dateien: Clang Python Bindings
  • 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 libcap-Bibliotheksheader und ein Build-Tool wie Ninja (empfohlen).

Bazel verwenden

Bazel ist das empfohlene Build-System und lässt sich am einfachsten einbinden.

In unserer Dokumentation wird der Clang-Compiler verwendet. Wenn Sie eine bestimmte Toolchain (z.B. Compiler, Linker usw.) benötigen, finden Sie in der Bazel-Dokumentation Informationen dazu, wie Sie die Standard-Compiler-Toolchain ändern.

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

Gentoo

Erforderliche Kernel-Optionen:

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, das Projektdateien für Build-Tools wie Ninja oder Make generiert.

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

Gentoo

Erforderliche Kernel-Optionen:

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

Wenn Sie eine C/C++-Bibliothek in einer Sandbox ausführen möchten, müssen Sie zwei Elemente für Ihr Projekt vorbereiten:

Vielleicht kennen Sie zlib aus den Sandbox2-Beispielen, in denen ein ganzes Programm (zpipe.c) in einer Sandbox ausgeführt wurde. In den folgenden Schritten erfahren Sie, wie Sie mit der SAPI die zlib-Bibliothek in einer Sandbox ausführen und die Sandboxed Library verwenden.

1. Entscheiden, welche Funktionen benötigt werden

Wenn Sie sich den Zlib-Hostcode (main_zlib.cc) ansehen, können Sie erkennen, dass das Tool Daten aus stdin liest und die deflate()-Funktion von Zlib verwendet, um die Daten zu komprimieren, bis ein EOF-Marker gelesen wird. Insgesamt verwendet das Programm drei Funktionen aus zlib:

  • deflateInit_(): Zur Initialisierung für die Komprimierung
  • deflate(): Zum Ausführen des Komprimierungsvorgangs für den Datenblock
  • deflateEnd(): Beendet die Komprimierung und gibt dynamisch zugewiesene Datenstrukturen kostenlos.

In einem realen Beispiel würden Sie die C/C++-Bibliothek prüfen 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. In einem zweiten Schritt könnten Sie dann die Sandbox-Bibliothek generieren und den Hostcode anpassen, um die Sandbox-Funktionsaufrufe zu verwenden.

2. Build-Regel für sapi_library schreiben

Nachdem Sie die drei zlib-Funktionen identifiziert haben, die aus der Sandbox-zlib-Bibliothek benötigt 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 Rules (Build-Regeln).

Das folgende Code-Snippet zeigt die sapi_library-Definition für das zlib SAPI-Beispiel. Mit dem Attribut 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",
)

Die Sandbox-zlib-Bibliothek wird generiert. Die Ausgabe ist das SAPI-Objekt, das in den Hostcode eingefügt werden kann und mit dem über RPC-Aufrufe mit der Sandbox-Bibliothek kommuniziert 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 einzubinden.

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 so die Sandbox-Funktionen zur Verfügung zu stellen.

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 sehen, wo ein SAPI-Struct 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 starten

Verwenden Sie das SAPI-Objekt, um Aufrufe an defalteInit_, deflate oder deflateEnd zu senden. Wenn Sie sich für die Methode „change“ entscheiden, müssen Sie darauf achten, dass die Funktionsparameter den erwarteten Werten entsprechen.

Hier ein Beispiel für jeden der 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 Sandbox-Bibliothek und gibt dem Aufrufer die Möglichkeit, problematische Datenverarbeitungsanfragen neu zu starten oder abzubrechen. SAPI-Transaktionen gehen noch einen Schritt weiter und wiederholen fehlgeschlagene Prozesse automatisch.

Weitere Informationen finden Sie auf der Seite SAPI Transactions.

Beispiele

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