Introduzione all'API Sandboxed

In questa pagina scoprirai come creare la tua libreria C/C++ in sandbox con Sandboxed API (SAPI). Utilizzala come guida insieme agli esempi e alla documentazione del codice nei file di intestazione.

Dipendenze build

Le seguenti dipendenze devono essere installate sul sistema:

  • Kernel Linux con supporto per gli spazi dei nomi UTS, IPC, utente, PID e di rete
  • Intestazioni API dello spazio utente Linux
  • Per compilare il codice: GCC 6 (versione 7 o successive consigliata) o Clang 7 (o versioni successive)
  • Per la generazione automatica dei file di intestazione: Clang Python Bindings
  • 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 build 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 del compilatore predefinita.

Debian 10 (Buster)

Per installare le dipendenze di 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 del kernel richieste:

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

Per installare le dipendenze di build:

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

Utilizzo di CMake

CMake è un sistema di meta-compilazione open source molto diffuso che genera file di progetto per strumenti di compilazione come Ninja o Make.

Debian 10 (Buster)

Per installare le dipendenze di 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 del kernel richieste:

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

Per installare le dipendenze di build:

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

Processo di sviluppo

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

Potresti conoscere zlib dagli esempi di Sandbox2 , dove è stato inserito in sandbox un intero programma (zpipe.c) . Nei passaggi che seguono, imparerai a utilizzare SAPI per inserire in sandbox la libreria zlib e utilizzare la libreria in sandbox.

1. Decidi quali funzioni sono necessarie

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

  • deflateInit_(): per inizializzare la compressione
  • deflate(): per eseguire l'operazione di compressione sul blocco di dati
  • deflateEnd(): per terminare la compressione e liberare le strutture di dati allocate dinamicamente

In un esempio reale, esamineresti la libreria C/C++ e decideresti quali funzioni sono necessarie. Una strategia possibile è iniziare con il codice host e utilizzare la libreria senza sandbox. Poi, in un secondo passaggio, potresti generare la libreria in sandbox e adattare il codice host per utilizzare le chiamate di funzione in sandbox.

2. Scrivi la regola di build sapi_library

Dopo aver identificato le tre funzioni zlib necessarie dalla libreria zlib in sandbox, puoi definire la regola di build nel file BUILD. La documentazione per la 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 SAPI zlib. Utilizzando l'attributo lib, Bazel riceve l'istruzione 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 è la generazione della libreria zlib in sandbox. L'output è l'oggetto SAPI che può essere incluso nel codice host e utilizzato per comunicare con la libreria in sandbox tramite chiamate RPC. Il criterio di sandbox utilizzato in questo esempio è il criterio predefinito.

3. Scrivi o modifica il codice host

Ora è il momento di incorporare la libreria SAPI generata nel codice host.

Crea la sandbox

Utilizza 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 rendere quindi disponibili le funzioni in sandbox.

Utilizza i tipi SAPI

I tipi SAPI sono tipi speciali sotto forma di classi C++ che SAPI fornisce perché a volte i tipi C normali non funzionano.

Il primo utilizzo di un tipo SAPI può essere osservato nella dichiarazione di strm, dove viene utilizzata una struttura 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 maggiori dettagli, consulta la pagina Variabili.

Esegui chiamate API

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

Un esempio di ciascuna delle chiamate nell'esempio 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 in sandbox e consente al chiamante di riavviare o interrompere le richieste di elaborazione dei dati problematiche. La transazione SAPI va oltre e ripete automaticamente i processi non riusciti.

Per maggiori dettagli, consulta la pagina Transazioni SAPI Page.

Esempi

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