Introduzione all'API Sandboxed

In questa pagina imparerai a creare la tua libreria C/C++ con sandbox tramite l'API Sandboxed (SAPI). Utilizzalo come guida insieme agli esempi e alla documentazione relativa al codice nei file di intestazione.

Crea dipendenze

Nel sistema devono essere installate le seguenti dipendenze:

  • Kernel Linux con supporto per gli spazi dei nomi UTS, IPC, utente, PID e di rete
  • Intestazioni API Linux userspace
  • Per compilare il codice: GCC 6 (preferito versione 7 o successiva) o Clang 7 (o successivo)
  • Per i file di intestazione generati automaticamente: associazioni Python Clang
  • Python 3.5 o versioni successive
  • Bazel versione 2.2.0 o CMake versione 3.12 o successive.
    • Solo CMake: GNU Make o una versione delle intestazioni della libreria libcap e uno strumento di creazione come Ninja (consigliato).

Utilizzo di Bazel

Bazel è il sistema di compilazione consigliato ed è il più facile da integrare.

La nostra documentazione utilizza il compilatore Clang. Se hai bisogno di una Toolchain specifica (ad es. compilatore, linker e così via), consulta la documentazione di Bazel per informazioni su come modificare la Toolchain predefinita del compilatore.

Debian 10 (Buster)

Per installare le dipendenze delle build:

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

Opzioni kernel obbligatorie:

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

Per installare le dipendenze delle build:

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

Utilizzo di CMake

CMake è un noto sistema di meta-build open source che genera file di progetto per strumenti di creazione come Ninja o Make.

Debian 10 (Buster)

Per installare le dipendenze delle build:

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

Opzioni kernel obbligatorie:

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

Per installare le dipendenze delle build:

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

Processo di sviluppo

Per eseguire il sandbox di una libreria C/C++, devi preparare due elementi per il tuo progetto:

Forse hai già dimestichezza con gli esempi di zlib degli esempi di Sandbox2, in questo caso un intero programma (zpipe.c) è stato limitato tramite sandbox. Nei passaggi seguenti, imparerai a utilizzare SAPI per eseguire la sandbox della libreria zlib e utilizzare quest'ultima.

1. Decidere quali funzioni sono necessarie

Se esamini il codice host di zlib (main_zlib.cc), puoi vedere che la funzionalità dello strumento è leggere i dati da stdin e utilizzare la funzione deflate() di zlib per comprimerli fino a quando non viene letto un indicatore EOF. In totale, il programma utilizza tre funzioni di zlib:

  • deflateInit_(): per inizializzare per la compressione
  • deflate(): per eseguire l'operazione di compressione sul blocco di dati.
  • deflateEnd(): per terminare la compressione e le strutture di dati distribuite in modo dinamico

In un esempio reale, esamineresti la libreria C/C++ e deciderai quali funzioni sono necessarie. Una possibile strategia consiste nell'iniziare con il codice host e utilizzare la libreria senza sandbox. Quindi, in un secondo passaggio, puoi generare la libreria con sandbox e adattare il codice host per utilizzare le chiamate alle funzioni con sandbox.

2. Scrivi la regola di build sapi_library

Dopo aver identificato le tre funzioni zlib necessarie dalla libreria zlib con sandbox, puoi definire la regola di compilazione nel file CREA. La documentazione relativa alla regola di build sapi_library è disponibile nella pagina Regole di build.

Lo snippet di codice riportato di seguito mostra la definizione di sapi_library per l'esempio di SAPI zlib. Utilizzando l'attributo lib, a Bazel viene chiesto di cercare la libreria zlib nel file WORKSPACE.

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

Il risultato è che viene generata la libreria zlib con sandbox. L'output è l'oggetto SAPI, che può essere incluso nel codice host e utilizzato per comunicare con la libreria sandbox tramite chiamate RPC. Il criterio della sandbox utilizzato in questo esempio è il criterio predefinito.

3. Scrittura o modifica del codice host

È arrivato il momento di incorporare la libreria SAPI generata nell'host Code.

Crea la sandbox

Usa sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); per creare un oggetto sandbox.

Utilizza sapi::zlib::ZlibApi api(&sandbox); per creare un'istanza dell'oggetto SAPI e quindi rendere disponibili per l'uso le funzioni con sandbox.

Utilizza tipi SAPI

I tipi SAPI sono tipi speciali sotto forma di classi C++ fornite da SAPI perché a volte i normali C-type non funzionano.

Il primo utilizzo di un tipo SAPI può essere osservato nella dichiarazione di strm, dove viene utilizzato uno struct SAPI: sapi::v::Struct<sapi::zlib::z_stream> strm;

Il tipo di modello (sapi::zlib::z_stream) è un buon esempio di codice generato automaticamente dalla regola di build.

Per ulteriori dettagli, consulta la pagina Variabili.

Effettua chiamate API

Per effettuare chiamate a defalteInit_, deflate o deflateEnd, utilizza l'oggetto SAPI. Se decidi di utilizzare l'approccio di "cambiamento", devi assicurarti che i parametri della funzione corrispondano ai valori previsti.

Un esempio di ciascuna delle chiamate nell'esempio di 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();

Utilizzo delle transazioni SAPI

SAPI isola il codice host dalla libreria con sandbox e offre al chiamante la possibilità di riavviare o interrompere le richieste di elaborazione dati problematiche. La transazione SAPI fa un passo in più e ripete automaticamente i processi non riusciti.

Per ulteriori dettagli, consulta la pagina Transazioni SAPI.

Esempi

Nella sezione Esempi puoi trovare alcune librerie già preparate dal team SAPI.