Pierwsze kroki z interfejsem Sandboxed API

Na tej stronie dowiesz się, jak utworzyć własną bibliotekę C/C++ w trybie piaskownicy za pomocą interfejsu Sandboxed API (SAPI). Wykorzystaj go jako przewodnik razem z przykładami i dokumentacją kodu w plikach nagłówka.

Tworzenie zależności

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

  • Jądro systemu Linux z obsługą przestrzeni nazw UTS, IPC, użytkownika, PID i sieciowych przestrzeni nazw
  • Nagłówki interfejsu Linux Userspace API
  • Aby skompilować kod: GCC 6 (preferowana wersja 7 lub nowsza) lub Clang 7 (lub nowsza)
  • Automatyczne generowanie plików nagłówka: powiązania Clang Python
  • Python 3.5 lub nowszy
  • Bazel w wersji 2.2.0 bądź CMake w wersji 3.12 lub nowszej.
    • Tylko CMake: GNU Make lub wersja nagłówków biblioteki libcap i narzędzia do kompilacji, np. Ninja (zalecane).

Korzystanie z Bazela

Zalecanym systemem kompilacji jest Bazel, który najłatwiej można zintegrować.

W naszej dokumentacji korzystamy z kompilatora Clang. Jeśli potrzebujesz konkretnego łańcucha narzędzi (np. kompilatora lub kreatora linków), zapoznaj się z dokumentacją Baidu, 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://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

Gentua

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 projektów na potrzeby 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

Gentua

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ć dwa elementy do swojego projektu:

Być może znasz zlib z przykładów piaskownicy2. Cały program (zpipe.c) jest w piaskownicy. Z kolei dowiesz się, jak korzystać z biblioteki w trybie piaskownicy za pomocą interfejsu SAPI i piaskownicy z biblioteki zlib.

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

Jeśli spojrzysz na kod hosta zlib (main_zlib.cc), zobaczysz, że jego funkcje to odczytywanie danych z pliku stdin i używanie funkcji deflate() zlib do skompresowania danych do momentu odczytania znacznika EOF. Łącznie program wykorzystuje 3 funkcje z zlib:

  • deflateInit_(): aby zainicjować w celu kompresji
  • deflate(): przeprowadza operację kompresji na fragmencie danych.
  • deflateEnd(): aby zakończyć kompresję i bezpłatne, dynamicznie przydzielane struktury danych

W praktyce warto przejrzeć bibliotekę C/C++ i zdecydować, które funkcje są potrzebne. Można zacząć od kodu hosta i używać biblioteki poza piaskownicą. Następnie można wygenerować Bibliotekę w trybie piaskownicy i dostosować kod hosta tak, aby wykorzystywał wywołania funkcji piaskownicy.

2. Napisz regułę kompilacji sapi_library

Po zidentyfikowaniu 3 funkcji zlib wymaganych w bibliotece zlib w trybie piaskownicy możesz zdefiniować regułę kompilacji w pliku BUILD. Dokumentację reguły kompilacji sapi_library znajdziesz na stronie Reguły kompilacji.

Fragment kodu poniżej zawiera definicję sapi_library dla przykładowego interfejsu SAPI zlib. Przy użyciu atrybutu lib Bazel ma znaleźć bibliotekę 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 efekcie zostanie wygenerowana biblioteka zlib w trybie piaskownicy. Dane wyjściowe to obiekt SAPI, który można umieścić w kodzie hosta i za jego pomocą komunikować się z biblioteką w trybie piaskownicy za pomocą wywołań RPC. Użyta w tym przykładzie zasada piaskownicy jest zasadą domyślną.

3. Zapisywanie lub zmienianie kodu hosta

Teraz należy włączyć wygenerowaną bibliotekę SAPI do kodu hosta.

Utwórz piaskownicę

Użyj polecenia sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create());, aby utworzyć obiekt piaskownicy.

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

Używanie typów SAPI

Typy SAPI to specjalne typy klas C++ udostępniane przez SAPI, ponieważ czasami zwykłe typy C nie działają.

Pierwsze użycie typu SAPI można zaobserwować w deklaracji strm, gdzie używany 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.

Wykonywanie wywołań interfejsu API

Aby wywoływać metody defalteInit_, deflate lub deflateEnd, użyj obiektu SAPI. Jeśli wybierzesz metodę „zmiany”, musisz upewnić się, że parametry funkcji są zgodne z oczekiwanymi wartościami.

Przykład każdego wywołania w przykładzie 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();

Korzystanie z transakcji SAPI

Interfejs SAPI izoluje kod hosta od biblioteki w trybie piaskownicy i daje elementowi wywołującemu możliwość ponownego uruchamiania lub przerywania problematycznych żądań przetwarzania danych. Transakcja SAPI idzie o krok dalej i automatycznie powtarza nieudane procesy.

Więcej informacji znajdziesz na stronie transakcji SAPI.

Przykłady

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