サンドボックス化された API のスタートガイド

このページでは、サンドボックス化された API(SAPI)を使用して、独自のサンドボックス化された C/C++ ライブラリを作成する方法を学びます。ヘッダー ファイル内のやコードのドキュメントと併せて、このガイドを参考にしてください。

ビルドの依存関係

次の依存関係をシステムにインストールする必要があります。

  • UTS、IPC、ユーザー、PID、ネットワークの名前空間をサポートする Linux カーネル
  • Linux ユーザー空間 API ヘッダー
  • コードをコンパイルするには: GCC 6(バージョン 7 以降が推奨)または Clang 7(以降)
  • 自動生成ヘッダー ファイルの場合: Clang Python バインディング
  • Python 3.5 以降
  • Bazel バージョン 2.2.0 または CMake バージョン 3.12 以降。
    • CMake のみ: GNU Make または libcap ライブラリ ヘッダーのバージョンと、Ninja などのビルドツール(推奨)。

Bazel の使用

Bazel は推奨のビルドシステムで、最も簡単に統合できます。

Google のドキュメントでは、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 は、NinjaMake などのビルドツール用のプロジェクト ファイルを生成する一般的なオープンソースのメタ ビルドシステムです。

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++ ライブラリをサンドボックス化するには、プロジェクト用に 2 つのアイテムを準備する必要があります。

サンドボックス 2 の例で紹介した zlib では、プログラム全体(zpipe.c)がサンドボックス化されています。次の手順では、SAPI を使用して zlib ライブラリをサンドボックス化し、サンドボックス ライブラリを使用する方法を学びます。

1. 必要な関数を決定する

zlib ホストコード(main_zlib.cc)を見ると、stdin からデータを読み取り、zlib の deflate() 関数を使用して EOF マーカーが読み取られるまでデータを圧縮するというのがツールの機能であることがわかります。このプログラムは全部で zlib の 3 つの関数を使用します。

  • deflateInit_(): 圧縮のために初期化する
  • deflate(): データチャンクの圧縮オペレーションを実行します。
  • deflateEnd(): 圧縮と、動的割り当ての自由なデータ構造を終了する

実際の例では、C/C++ ライブラリを確認して、必要な関数を決定します。考えられる戦略は、ホストコードから開始し、サンドボックス化せずにライブラリを使用することです。次に、2 つ目の手順として、サンドボックス化されたライブラリを生成し、サンドボックス化された関数呼び出しを使用するようにホストコードを調整します。

2. sapi_library ビルドルールを作成する

サンドボックス化された zlib ライブラリで必要な zlib 関数を 3 つ特定したら、BUILD ファイルでビルドルールを定義できます。sapi_library ビルドルールのドキュメントは [ビルドルール] ページをご覧ください。

以下のコード スニペットは、zlib SAPI の例の sapi_library 定義を示しています。lib 属性を使用して、Bazel は WORKSPACE ファイルで zlib ライブラリを探すように指示されます。

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 構造体が使用されています: sapi::v::Struct<sapi::zlib::z_stream> strm;

テンプレート タイプ(sapi::zlib::z_stream)は、ビルドルールで自動的に生成されるコードの好例です。

詳しくは、[変数] ページをご覧ください。

API 呼び出しを行う

defalteInit_deflatedeflateEnd のいずれかを呼び出すには、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 トランザクションのページをご覧ください。

[Examples] の下には、すでに SAPI チームによって準備されているライブラリがいくつか含まれています。