Начало работы с изолированным API

На этой странице вы узнаете, как создать собственную изолированную библиотеку C/C++ с помощью Sandboxed API (SAPI). Используйте её в качестве руководства наряду с примерами и документацией по коду в заголовочных файлах.

Зависимости сборки

В системе должны быть установлены следующие зависимости:

  • Ядро Linux с поддержкой пространств имен UTS, IPC, пользователя, PID и сети
  • Заголовки API пользовательского пространства Linux
  • Для компиляции кода: GCC 6 (предпочтительно версии 7 или выше) или Clang 7 (или выше)
  • Для автоматической генерации заголовочных файлов: Clang Python Bindings
  • Python 3.5 или более поздняя версия
  • Bazel версии 2.2.0 или CMake версии 3.12 или выше.
    • Только CMake: GNU Make или версия заголовочных файлов библиотеки libcap и инструмент сборки, такой как Ninja (рекомендуется).

Использование Базеля

Bazel — рекомендуемая система сборки, с которой проще всего интегрироваться.

В нашей документации используется компилятор Clang. Если вам нужен конкретный набор инструментов (например, компилятор, линкер и т. д.), обратитесь к документации Bazel за информацией о том, как изменить набор инструментов компилятора по умолчанию.

Debian 10 (Buster)

Чтобы установить зависимости сборки:

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

Генту

Требуемые параметры ядра:

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

Чтобы установить зависимости сборки:

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

Использование CMake

CMake — популярная система метасборки с открытым исходным кодом, которая генерирует файлы проекта для инструментов сборки, таких как Ninja или Make .

Debian 10 (Buster)

Чтобы установить зависимости сборки:

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

Генту

Требуемые параметры ядра:

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

Чтобы установить зависимости сборки:

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

Процесс разработки

Чтобы изолировать библиотеку C/C++, вам придется подготовить два элемента для вашего проекта:

Возможно, вы знакомы с zlib по примерам Sandbox2 , где целая программа ( zpipe.c ) была изолирована. Далее вы узнаете, как использовать SAPI для изоляции библиотеки zlib и использования изолированной библиотеки.

1. Решите, какие функции необходимы

Если взглянуть на код хоста zlib ( main_zlib.cc ), можно увидеть, что функционал инструмента заключается в чтении данных из стандартного ввода (stdin) и использовании функции deflate() из zlib для сжатия данных до тех пор, пока не будет прочитан маркер конца EOF . Всего программа использует три функции из zlib:

  • deflateInit_() : для инициализации сжатия
  • deflate() : выполнить операцию сжатия фрагмента данных
  • deflateEnd() : завершение сжатия и освобождение динамически выделенных структур данных

В реальном примере вы бы изучили библиотеку C/C++ и определили, какие функции необходимы. Возможная стратегия — начать с кода хоста и использовать библиотеку без изоляции. Затем, на втором этапе, можно сгенерировать библиотеку для изоляции и адаптировать код хоста для использования вызовов функций, выделенных в песочницу.

2. Напишите правило сборки sapi_library

После того, как вы определили три необходимые функции zlib из изолированной библиотеки zlib, вы можете определить правило сборки в файле BUILD . Документацию по правилу сборки sapi_library можно найти на странице «Правила сборки» .

Фрагмент кода ниже показывает определение sapi_library для примера SAPI zlib. Используя атрибут lib , Bazel получает указание искать библиотеку zlib в файле WORKSPACE .

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

Результатом является создание изолированной библиотеки zlib. Результатом является объект SAPI, который можно включить в код хоста и использовать для взаимодействия с изолированной библиотекой посредством RPC-вызовов. Политика песочницы, используемая в этом примере, является политикой по умолчанию.

3. Напишите или измените код хоста

Теперь пришло время включить сгенерированную библиотеку SAPI в код хоста.

Создать песочницу

Используйте sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); для создания объекта песочницы.

Используйте sapi::zlib::ZlibApi api(&sandbox); для создания экземпляра объекта SAPI и, таким образом, сделайте изолированные функции доступными для использования.

Использовать типы SAPI

Типы SAPI — это специальные типы в форме классов C++, которые предоставляет SAPI, поскольку иногда обычные типы C не работают.

Первое использование типа SAPI можно наблюдать в объявлении strm , где используется SAPI Struct: sapi::v::Struct<sapi::zlib::z_stream> strm;

Тип шаблона ( sapi::zlib::z_stream ) является хорошим примером кода, автоматически сгенерированного правилом сборки.

Более подробную информацию можно найти на странице Переменные .

Выполнять вызовы API

Для вызова defalteInit_ , deflate или deflateEnd используйте объект SAPI. Если вы решите использовать подход «изменение», необходимо убедиться, что параметры функции соответствуют ожидаемым значениям.

Пример каждого из вызовов в примере 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();

Использование транзакций SAPI

SAPI изолирует код хоста от изолированной библиотеки и предоставляет вызывающему объекту возможность перезапускать или прерывать проблемные запросы на обработку данных. SAPI-транзакция идёт ещё дальше и автоматически повторяет неудачные процессы.

Более подробную информацию можно найти на странице транзакций SAPI .

Примеры

В разделе «Примеры» вы найдете несколько библиотек, уже подготовленных командой SAPI.