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.
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:
- In einer Sandbox ausgeführte Bibliothek
- Den Hostcode, der die Funktionen Ihrer Sandbox-Bibliothek nutzt. SAPI generiert das SAPI-Objekt und den RPC-Stub während des Build-Prozesses automatisch für Sie.
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 Komprimierungdeflate()
: zum Ausführen der Komprimierung für den DatenblockdeflateEnd()
: 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.