1. サンドボックス エグゼキュータ メソッドを選択する

サンドボックス化は、エグゼキュータ(サンドボックス エグゼキュータを参照)から始まります。エグゼキュータは Sandboxee を実行します。executor.h ヘッダー ファイルには、この目的に必要な API が含まれています。API は非常に柔軟性が高く、ユースケースに最適なものを選択できます。以下のセクションでは、この 3 種類の方法について説明します。

方法 1: スタンドアロン - サンドボックス化がすでに有効になっているバイナリを実行する

これはサンドボックスを使用する最も簡単な方法であり、ソースコードがないバイナリ全体をサンドボックス化したい場合に推奨される方法です。また、悪影響を及ぼす可能性があるサンドボックス化されていない初期化はないため、サンドボックスを使用する最も安全な方法です。

次のコード スニペットでは、サンドボックス化するバイナリのパスと、execve システムコールに渡す必要がある引数を定義しています。executor.h ヘッダー ファイルを見るとわかるように、envp の値は指定しないため、親プロセスから環境をコピーします。最初の引数は常に実行するプログラムの名前で、スニペットは他の引数を定義しません。

エグゼキュータ メソッドには、たとえば statictool があります。

#include "sandboxed_api/sandbox2/executor.h"

std::string path = "path/to/binary";
std::vector<std::string> args = {path};  // args[0] will become the sandboxed
                                         // process' argv[0], typically the
                                         // path to the binary.
auto executor = absl::make_unique<sandbox2::Executor>(path, args);

方法 2: Sandbox2 Forkserver - サンドボックス化するタイミングをエグゼキュータに伝える

この方法では、初期化時にサンドボックス化を解除し、::sandbox2::Client::SandboxMeHere() を呼び出してサンドボックス化を開始するタイミングを選択できます。サンドボックス化を開始するときは、コード内で定義でき、シングル スレッドである必要があります(よくある質問をご覧ください)。

次のコード スニペットでは、上記の方法 1 で説明したものと同じコードを使用します。ただし、初期化時にプログラムをサンドボックス化されていない方法で実行できるように、set_enable_sandbox_before_exec(false) を呼び出します。

#include "sandboxed_api/sandbox2/executor.h"

std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto executor = absl::make_unique<sandbox2::Executor>(path, args);
executor->set_enable_sandbox_before_exec(false);

Sandboxee から通知されるまでエグゼキュータのサンドボックスが無効になるため、::sandbox2::Client インスタンスを作成してエグゼキュータと Sandboxee 間の通信を設定してから、初期化が完了したこと、sandbox2_client.SandboxMeHere() を呼び出してサンドボックス化を開始することをエグゼキュータに通知する必要があります。

// main() of sandboxee
int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, false);

  // Set-up the sandbox2::Client object, using a file descriptor (1023).
  sandbox2::Comms comms(sandbox2::Comms::kSandbox2ClientCommsFD);
  sandbox2::Client sandbox2_client(&comms);
  // Enable sandboxing from here.
  sandbox2_client.SandboxMeHere();
  …

このエグゼキュータ メソッドの例は、crc4 です。crc4bin.cc は Sandboxee であり、サンドボックスに入るときにエグゼキュータ(crc4sandbox.cc)に通知します。

方法 3: カスタム フォークサーバー - バイナリを準備し、フォーク リクエストを待ってから、独自にサンドボックスを構築する

このモードでは、バイナリを開始し、サンドボックス化のために準備し、バイナリのライフサイクルの特定の時点でエグゼキュータで使用できるようにします。

エグゼキュータはフォーク リクエストをバイナリに送信し、バイナリは(::sandbox2::ForkingClient::WaitAndFork() を介して)fork() します。新しく作成されたプロセスは、::sandbox2::Client::SandboxMeHere() でサンドボックス化する準備が整います。

#include "sandboxed_api/sandbox2/executor.h"

// Start the custom ForkServer
std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto fork_executor = absl::make_unique<sandbox2::Executor>(path, args);
fork_executor->StartForkServer();

// Initialize Executor with Comms channel to the ForkServer
auto executor = absl::make_unique<sandbox2::Executor>(
    fork_executor->ipc()->GetComms());

このモードは非常に複雑で、限られたメモリ要件があるなど、いくつかの特定のケースにのみ適用されます。COW にはメリットがありますが、真の ASLR がないという欠点があります。もう一つの一般的な使用例としては、Sandboxee で、信頼できないデータが処理される前に、CPU 負荷の高い初期化を長時間実行できる場合が挙げられます。

このエグゼキュータ メソッドの例については、custom_fork をご覧ください。