Pierwsze kroki z interfejsem Sandboxed API

Na tej stronie dowiesz się, jak utworzyć własną bibliotekę C/C++ w piaskownicy za pomocą Sandboxed API (SAPI). Korzystaj z niej jako przewodnika, a także z przykładów i dokumentacji kodu w plikach nagłówkowych.

Zależności kompilacji

W systemie muszą być zainstalowane te zależności:

  • jądro Linuxa z obsługą przestrzeni nazw UTS, IPC, użytkownika, PID i sieci;
  • nagłówki interfejsu API przestrzeni użytkownika Linuxa;
  • do kompilowania kodu: GCC 6 (zalecana wersja 7 lub nowsza) lub Clang 7 (lub nowszy);
  • do automatycznego generowania plików nagłówkowych: powiązania Clang Python;
  • Python 3.5 lub nowszy;
  • Bazel w wersji 2.2.0 lub CMake w wersji 3.12 lub nowszej.
    • Tylko CMake: GNU Make lub wersja nagłówków biblioteki libcap oraz narzędzie do kompilacji, np. Ninja (zalecane).

Korzystanie z usługi Bazel

Bazel to zalecany system kompilacji, który najłatwiej zintegrować.

W naszej dokumentacji używamy kompilatora Clang. Jeśli potrzebujesz konkretnego łańcucha narzędzi (np. kompilatora, linkera itp.), zapoznaj się z dokumentacją Bazela, aby dowiedzieć się, jak zmienić domyślny łańcuch narzędzi kompilatora.

Debian 10 (Buster)

Aby zainstalować zależności kompilacji:

echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://releases.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

Wymagane opcje jądra:

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

Aby zainstalować zależności kompilacji:

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

Korzystanie z CMake

CMake to popularny system metakompilacji typu open source, który generuje pliki projektu dla narzędzi do kompilacji, takich jak Ninja czy Make.

Debian 10 (Buster)

Aby zainstalować zależności kompilacji:

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

Wymagane opcje jądra:

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

Aby zainstalować zależności kompilacji:

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

Proces programowania

Aby umieścić bibliotekę C/C++ w piaskownicy, musisz przygotować 2 elementy projektu:

Możesz znać zlib z przykładów Sandbox2 . W tym przypadku cały program (zpipe.c) został umieszczony w piaskownicy. W kolejnych krokach dowiesz się, jak używać SAPI do umieszczania biblioteki zlib w piaskownicy i korzystania z biblioteki w piaskownicy.

1. Określ, które funkcje są potrzebne

Jeśli przyjrzysz się kodowi hosta zlib (main_zlib.cc), zobaczysz, że narzędzie odczytuje dane ze standardowego wejścia i używa funkcji zlib deflate() do kompresowania danych do momentu odczytania znacznika EOF. Program używa łącznie 3 funkcji zlib:

  • deflateInit_(): do inicjowania kompresji;
  • deflate(): do wykonywania operacji kompresji na porcji danych;
  • deflateEnd(): do zakończenia kompresji i zwolnienia dynamicznie przydzielonych struktur danych.

W rzeczywistym przykładzie przejrzysz bibliotekę C/C++ i określisz, które funkcje są potrzebne. Możesz zacząć od kodu hosta i używać biblioteki bez piaskownicy. Następnie możesz wygenerować bibliotekę w piaskownicy i dostosować kod hosta, aby używać wywołań funkcji w piaskownicy.

2. Napisz regułę kompilacji sapi_library

Po zidentyfikowaniu 3 funkcji zlib, które są potrzebne z biblioteki zlib w piaskownicy, możesz zdefiniować regułę kompilacji w pliku BUILD. Dokumentację reguły kompilacji sapi_library znajdziesz na stronie Reguły kompilacji.

Poniższy fragment kodu pokazuje definicję sapi_library na potrzeby przykładu SAPI zlib. Za pomocą atrybutu lib Bazel otrzymuje instrukcję, aby poszukać biblioteki zlib w pliku WORKSPACE.

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

W rezultacie generowana jest biblioteka zlib w piaskownicy. Wynikiem jest obiekt SAPI, który można uwzględnić w kodzie hosta i używać do komunikacji z biblioteką w piaskownicy za pomocą wywołań RPC.

Ten przykład używa domyślnej konfiguracji piaskownicy udostępnianej przez DefaultConfig (sapi::SandboxConfig::DefaultConfig()).

3. Napisz lub zmień kod hosta

Teraz możesz włączyć wygenerowaną bibliotekę SAPI do kodu hosta.

Utwórz piaskownicę

Aby utworzyć obiekt piaskownicy, użyj sapi::zlib::ZlibSandbox sandbox;.

Aby utworzyć instancję obiektu SAPI i udostępnić funkcje w piaskownicy do użycia, użyj sapi::zlib::ZlibApi api(&sandbox);.

Aby dostosować zasady piaskownicy, flagi, zmienne środowiskowe lub limity, zacznij od sapi::SandboxConfig::DefaultConfig(), zmodyfikuj odpowiednie pola (używając sapi::Sandbox2Config::DefaultPolicyBuilder(), sapi::SandboxConfig::DefaultFlags(), lub sapi::SandboxConfig::DefaultEnvironmentVariables(), aby zachować ustawienia podstawowe), i przekaż sapi::SandboxConfig do konstruktora piaskownicy:

sapi::SandboxConfig config = sapi::SandboxConfig::DefaultConfig();
config.sandbox2.policy = sapi::Sandbox2Config::DefaultPolicyBuilder()
                             .AddFile("/path/to/file")
                             .BuildOrDie();
auto flags = sapi::SandboxConfig::DefaultFlags();
flags["my_flag"] = "value";
config.command_line_flags = std::move(flags);

sapi::zlib::ZlibSandbox sandbox(std::move(config));

Używaj typów SAPI

Typy SAPI to specjalne typy w postaci klas C++, które udostępnia SAPI, ponieważ czasami zwykłe typy C nie działają.

Pierwsze użycie typu SAPI można zaobserwować w deklaracji strm, gdzie używana jest struktura SAPI: sapi::v::Struct<sapi::zlib::z_stream> strm;

Typ szablonu (sapi::zlib::z_stream) jest dobrym przykładem kodu automatycznie generowanego przez regułę kompilacji.

Więcej informacji znajdziesz na stronie Zmienne.

Wykonuj wywołania interfejsu API

Aby wykonywać wywołania defalteInit_, deflate lub deflateEnd, użyj obiektu SAPI. Jeśli zdecydujesz się użyć podejścia „change”, musisz się upewnić, że parametry funkcji pasują do oczekiwanych wartości.

Przykład każdego z wywołań w przykładzie zlib example:

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

Korzystanie z transakcji SAPI

SAPI izoluje kod hosta od biblioteki w piaskownicy i umożliwia wywołującemu ponowne uruchomienie lub przerwanie problematycznych żądań przetwarzania danych. Transakcja SAPI idzie o krok dalej i automatycznie powtarza nieudane procesy.

Więcej informacji znajdziesz na stronie Transakcje SAPI Page.

Przykłady

W sekcji Przykłady znajdziesz kilka bibliotek przygotowanych przez zespół SAPI.