サーバーレスサンドボックスの全景:ptraceからDandelionまで
サーバーレスサンドボックスの全景:ptraceからDandelionまで
ここ数ヶ月、サーバーレスサンドボックスの設計空間全体をマッピングする10本のシステム論文を読んでいた。この記事は論文ごとのまとめではない。フィールドがどこへ向かっているかを定義する断層線——緊張、収束点、トレードオフ——を特定する試みだ。サーバーレスサンドボックス(Shimmy)を実際に構築している者として書いているので、レンズは実用的だ:今日実際に何を構築するか?
根本的な緊張
すべてのサンドボックスは同じ取引を交渉する:隔離の強度対実行オーバーヘッド。読んだ論文はスペクトル全体にわたり、コストは十分に定量化されていて明確な絵を描ける。
一方の極端では、ptraceが完全な制御を与える——すべてのsyscallを傍受し、すべての引数を検査し、任意のロジックを実行——フックあたり31,201 nsで。もう一方の極端では、DandelionのCHERIバックエンドがsyscallを完全に排除することで90マイクロ秒未満のコールドスタートを達成する。この両極の間で、すべてはトレードオフだ。
全景はおおよそ4つの戦略に分類される:
- カーネル境界で介入する(ptrace、seccomp、SUD、バイナリ書き換え)
- VMMを特化させる(Firecracker)
- カーネル境界をソフトウェア隔離で置き換える(Faasm/WebAssembly、Enclosure/MPK)
- カーネル境界を排除する(Dandelion、SigmaOS)
驚いたのは、これらが明確に進化的な順序を形成していることだ。各世代は前の世代のボトルネックを解決するが、新たな制約を導入する。フィールドは収束しつつあり、収束点はほとんどの人が期待するところではない。
syscall介入トリロジー:zpoline、lazypoline、K23
zpolineからK23への系譜は反復的なシステム設計の傑作だ。各論文は前任者が残した正確な欠点を解決する。
zpoline(ATC 2023)は美しいトリックを発見した:x86-64では syscall は2バイト、call rax も2バイト。rax がsyscall番号(小さな整数)を保持するため、syscall を call rax に書き換えると、仮想アドレス0のnopスレッドに実行がジャンプし、トランポリンにスライドする。コスト:フックあたり41 ns——ptraceより761倍速い。呼び出し規約がすでに rax を小さな範囲に制約しているという洞察は、後から見ると明らかに見えるが、発見するのに真の創造性が必要だった種類の観察だ。
欠点:zpolineはロード時に書き換える。JITコンパイルされたコード、動的にロードされたライブラリ、セットアップ後に生成されたもの——見えない。真に網羅的ではない。
lazypoline(DSN 2024)はハイブリッド設計でこれを修正した。LinuxのSyscall User Dispatch(SUD)をスローパスとして使う:見たことのない syscall 命令が実行されると、カーネルはSIGSYSを配信する。シグナルハンドラがzpoline式に書き換え、その後のすべての実行がファストパスを取る。レイジーリライティングのパターン——信頼できるが遅いメカニズムを使って最適化が必要なものを発見し、次にファストメカニズムをインストールする——はsyscall介入を超えて広く適用できる。パフォーマンス:Webサーバベンチマークで94〜95%のベースライン、網羅性を保証しながら。
でもlazypolineはより深い問題も明らかにした。論文のABI解析(Intel Pinを使用)は、coreutils一般の40〜100%が拡張CPU状態(SSE/AVX/x87)がsyscall全体で保存されることを期待していることを明らかにした。すべての以前のバイナリ書き換えはこの状態をサイレントに破損させていた。この発見だけで——すべての以前の書き換えに潜在的なバグがあったことが——論文の価値を正当化する。
K23(Middleware 2025)はzpolineとlazypolineの両方における5つのクラスの落とし穴を体系的にカタログ化した:LD_PRELOAD回避(execve の前に環境変数をクリアするとinterposerが消える)、prctl によるSUD無効化、静的逆アセンブリの誤識別、検証なしのNULL実行、非原子的ランタイム書き換え。K23の応答は2フェーズ設計だ:ホットなsyscallサイトを特定するオフラインプロファイリング、それらのサイトのみのオンライン選択的書き換え、ptraceがブートシーケンスをカバーし、SUDがフォールバックとして機能する。結果:98.62%のベースラインスループット——5つの落とし穴クラスすべてを処理する唯一のシステムでありながら、zpolineの98.93%に本質的に匹敵する。
lazypolineが命名した網羅性・効率性・表現力のトリレンマは解決可能だが、解決策は3つの別々のメカニズム(ブート用のptrace、ホットパス用のバイナリ書き換え、残り用のSUD)の組み合わせを必要とする。単一メカニズム介入の時代は終わった。
syscall介入が解決できないこと
K23でさえ避けられない税金を払う:単にSUDを有効にするだけで、傍受されていないsyscallでさえ全syscallに1.23倍のオーバーヘッドが加わる。カーネルがすべてのsyscallエントリでセレクタバイトをチェックするからだ。これはユーザスペースのトリックで排除できないカーネルレベルのコストだ。そしてアプローチ全体がx86-64のみに留まる——zpolineのnopスレッドトリックは可変長命令とアラインメントされていないジャンプに依存しており、ARMやRISC-Vには存在しない。
より根本的に、これらのシステムはすべて、サンドボックスするコードと同じアドレス空間で動作する。直交した隔離メカニズム(MPK、ハードウェア仮想化、CHERI)なしでは、十分に動機付けられた攻撃者がトランポリン、セレクタバイト、またはinterposer自体を上書きできる。論文はこれについて正直だ——K23は明示的に「直交するプロセス内隔離メカニズム」に言及している——しかしそれはsyscall介入単独ではサンドボックスではないことを意味する。防衛スタックの一層に過ぎない。
MicroVMへの賭け:Firecracker
Firecracker(NSDI 2020)の核心的な洞察は見かけ上シンプルだ:VMMを特化させる、OSではなく。新しいOSや新しい隔離メカニズムを構築する代わりに、QEMUを最小限まで削ぎ落とす:QEMUの140万行のCに対して5万行のRust。KVMを維持する。Linuxゲストカーネルを維持する。BIOS、PCI、VMマイグレーション、Windowsサポート、40以上のエミュレートされたデバイスを削除する。残るのはVM当たり3MBオーバーヘッド(QEMUの131MBに対して)、〜125msブート、ハードウェア仮想化の完全な隔離保証を持つVMMだ。
サーバーレス経済にとって重要な数字:128MB関数メモリでQEMUはVMMオーバーヘッドで100%を無駄にする;Firecrackerは2.3%。これは単一のマシンで8,000と100,000以上の関数を実行する差だ。
FirecrackerのJailerは多層防御パターンとして参考になる:ユーザコードをハードウェア隔離されたVMの内部に配置した後でも、VMM自体がchrootで実行され、許可されたsyscallは24個、ioctlは30個だ。VMMが侵害された場合、攻撃者は別のサンドボックスに降り立つ。この「サンドボックスをサンドボックスする」アプローチはどの設計から盗む価値もある。
Firecrackerが手放すのはコールドスタートだ。スナップショット復元でさえ、ゲストOSは不可避のコストを表す。Dandelionの測定によれば、Firecrackerのスナップショット復元の8msはゲストOSスナップショットのロードとホスト・ゲストネットワーキングの再構築に行く——その唯一の目的がユーザコードにPOSIXライクなインターフェースを提供することである操作に。この観察が次世代を駆動する。
No-OSフロンティア:Faasm、SigmaOS、Dandelion
3つの論文がOS境界を完全に排除する方向に押し進める、それぞれ異なる角度から。
Faasm(ATC 2020)はWebAssemblyのリニアメモリモデルを隔離プリミティブとして使う。すべての関数はゼロベースのオフセットでアクセスされる連続したバイト配列を受け取る;WebAssemblyランタイムがコンパイル時に境界を強制し、違反時にトラップする。リソース隔離はLinuxのcgroupsから来る。結果:Proto-Faasletスナップショットによる0.5msコールドスタート(Dockerより5,600倍速い)、インスタンスあたり90KBメモリ(コンテナより15倍少ない)、隔離を壊さずに共有メモリ領域を通じて同一ホスト上の関数間で状態を共有できる。Faasm はコンテナがサーバーレス隔離の唯一の実行可能なメカニズムではないことを証明した。
WebAssemblyの税金は本物だが:32ビットアドレス空間の制限とコンパイラ最適化の欠如により、一部のベンチマークで40〜240%の計算オーバーヘッド。データ集約的な並列ワークロード(Fasmの2層共有メモリ状態アーキテクチャが輝くところ)では、分散スピードアップが十分に補償する。計算ヘビーな単一関数では、痛みがある。
SigmaOS(SOSP 2024)はクラウドネイティブの角度から攻める。重要な観察:現代のクラウドアプリケーションはローカルOSリソースではなく、クラウドインフラ(S3、API、データベース)と対話する。関数をクラウド中心のAPIに制限すると、最もコストのかかる2つのコンテナ操作を排除できる:オーバーレイファイルシステム作成(〜5ms)とネットワーク名前空間作成(〜100ms)。SigmaOSのsigma-containerはDockerの352に対して67のsyscallのみ許可し、ネットワークsyscallを完全にブロックする——接続は認証後にファイルディスクリプタを引き渡す信頼できるプロキシを通じる。コールドスタート:7.7ms。トレードオフ:既存のLinuxアプリケーションとの後方互換性なし。
Dandelion(SOSP 2025)は最も急進的な立場を取る。アプリケーションを純粋な計算関数(syscallなし、ネットワーキングなし、スレッドなし)と通信関数(HTTPを処理する信頼できるプラットフォームコード)に分解する。計算関数はsyscallサポートを必要としないためゲストOSを必要としないサンドボックスで実行される。I/Oはサンドボックスの外で完全に行われる。結果は印象的だ:CHERI バックエンドのコールドスタートが90マイクロ秒未満、KVMバックエンドが889マイクロ秒(ゲストカーネルなし)、そして——すべてのクラウドエコノミストの注目を集めるべき数字——Knative自動スケーリング(Firecracker)と比較してコミットメモリが96%削減、リクエストごとのサンドボックス作成がアイドルインスタンスの事前ウォームの必要を排除するためだ。
Dandelionのdlibcは標準Cインターフェース(malloc、ファイルI/O)を提供し、ユーザースペースの仮想ファイルシステムを通じて入出力セットがファイルとして現れる。syscallは一切発行されない。TCBは隔離とユーザーコードに直接触れる〜2KラインのRustに縮小する、Firecrackerの〜68Kラインに対して。
これらのアプローチが収束するかどうかという問いがある。私はそうなると思う。Faasm はコンテナを排除した。SigmaOS はオーバーレイファイルシステムとネットワーク名前空間を排除した。Dandelionはゲストカーネルとsyscallインターフェースを排除した。軌跡は明確だ:カーネル境界はサーバーレス実行のクリティカルパスから押し出されつつある。何が代わるかは信頼モデルによる。
seccomp-eBPF:ステートフルフィルタ
seccomp-eBPF論文(arXiv 2023)は異なる問題を扱う:カーネル自身のフィルタリングメカニズムを有用になるほど強力にすること。クラシックなseccomp-BPFはステートレスで、ポインタをデリファレンスできず、同期プリミティブがなく、4096命令に制限される。これにより実際のデプロイメントは過度に許容的にならざるを得ない——cBPFが「初期化中は一度許可し、その後は拒否」を表現できないため、コンテナはライフタイム全体を通じて exec を許可しなければならない。
eBPFはこれを変える。論文はステートフルフィルタ(syscall呼び出し回数のカウント、一時的特化の実装)、安全なユーザースペースメモリアクセス(TOCTTOUを防ぐためのカーネルバッファへのコピー)、syscallのシリアル化(競合するsyscallをシリアル化させる原子変数)を導入する。一時的特化の結果は説得力がある:起動フェーズのみのsyscallをスタートアップ後に制限することで、6つのサーバーアプリケーションにわたって攻撃面が33〜55%削減される。
パフォーマンスの話はクリーンだ:eBPFフィルタは最適化されたcBPFのオーバーヘッドに一致(〜60サイクル)、SeccompNotifier(ユーザースペースエージェント)は45倍遅い。これによりeBPFが静的許可リスト以上のことが必要なフィルタの明確なパスになる。
落とし穴:seccomp-eBPFはメインラインのLinuxにマージされていない。LPCでのメンテナの反応は事実上「SeccompはeBPFを必要としない」だった。これは技術的な問題ではなく政治的な問題であり、それに依存することを計画している人にとって重要だ。
プロセス内隔離:軽量コンテキストとEnclosure
2つの論文がカーネル境界を完全に回避して、単一プロセス内の隔離を探求する。
軽量コンテキスト(OSDI 2016)はFreeBSDに新しいOS抽象を追加した:lwCはスレッドを共有するが独立した仮想メモリマッピング、ファイルディスクリプタテーブル、クレデンシャルを持つ。lwC間の切り替えコストは2マイクロ秒——プロセスのコンテキストスイッチの半分——なぜならPCIDタグ付きTLBエントリによるCR3レジスタスワップに過ぎないからだ。nginxの評価はスループットへの影響が無視できることを示した。SSLキー隔離(プライベートキーを別のlwCに入れる)は10,000ハンドシェイクで0.7%のオーバーヘッドだった。スナップショット/ロールバックパターン——リクエスト処理前にlwCスナップショットを取り、その後すべての状態を破棄する——はサーバーレスにとって優雅だ:コンテナの再起動なしで呼び出し間の情報漏洩がないことを保証する。
永続する教訓:隔離は高コストである必要はない。lwCが(2016年の論文にもかかわらず)Linuxに移植されなかったことは、技術的な失敗ではなく社会的な失敗だ。
Enclosure(ASPLOS 2021)は言語統合アプローチを取る。GoとPythonを with 構文で拡張し、クロージャをメモリビュー(どのパッケージがアクセス可能か)とsyscallフィルタにバインドする。LitterBoxバックエンドはIntel VT-x(924nsスイッチ)またはIntel MPK(86nsスイッチ)のいずれかを使ってこれらのポリシーを強制する。MPKバックエンドはHTTPワークロードで1.02倍のオーバーヘッドを達成する。
Enclosureの洞察は、パッケージがプロセス内隔離の自然な単位だということだ。デフォルトポリシー——自然な依存関係のみ可視、すべてのsyscallブロック——は開発者が実際に信頼について考える方法と一致する:「自分のコードは信頼する;このpipパッケージは信頼しない」。将来のLitterBoxバックエンドとしてのCHERIの論文の議論は先見的だ:ケーパビリティハードウェアはMPKの16キー制限を排除し、ページアライメント制約なしでオブジェクト粒度の隔離を可能にする。
向かっている場所
これら10本の論文を順番に読むと、3つのトレンドが明確に浮かび上がる。
第一に、カーネル境界は隔離の独占を失いつつある。 Firecrackerは信頼境界をハイパーバイザに移動させた。FasmはWebAssemblyランタイムに移動させた。Dandelionは2Kラインの Rust出力パーサに移動させた。Enclosureはコンパイラが強制するパッケージ境界にハードウェアバックアップのメモリビューで移動させた。各システムが、「プロセス」はサーバーレスワークロードのための唯一の——または最良の——隔離単位ではないことを示している。
第二に、ハードウェアはソフトウェアの野望に追いつきつつある。 Intel MPKは86nsのドメインスイッチを可能にする。ARM Morello(CHERI)は単一アドレス空間での90マイクロ秒未満のサンドボックス作成を可能にする。CHERIケーパビリティモデル——すべてのポインタが自分自身の境界と権限を持ち、すべてのメモリアクセスでハードウェアによって強制される——はプロセス内隔離のエンドゲームを表す。EnclosureがCHERIを将来のバックエンドとして議論し、DandelionがすべてのCHERI代替より速いCHERI隔離バックエンドを実装するとき、彼らは同じ未来を指し示している:ハードウェア強制ケーパビリティがカーネルを主要な隔離プリミティブとして置き換える。
第三に、「no-syscall」設計ポイントは実行可能であり、おそらく最適だ。 Dandelionは、意味のあるクラスのワークロード(データ処理、ML推論、クエリ実行、エージェントAIワークフロー)に対して、syscallを完全に排除する——フィルタリングでも介入でもなく、排除する——ことがコールドスタート、メモリ密度、テールレイテンシの安定性において桁違いの改善をもたらすことを証明した。96%のメモリ削減と2〜3桁の分散削減は漸進的な改善ではない。それらは異なる動作レジームを表す。
今日私が構築するもの
新しいサーバーレスプラットフォームをゼロから始めるとしたら——そして私はShimmyで実際にそうしているが——論文の全景が私に教えることはここにある。
プラグイン可能な隔離バックエンドを持つレイヤードアーキテクチャを使う。 Dandelionがこれを正しく理解した:同じスケジューラと実行エンジンが信頼モデルによってKVM、プロセス、CHERI、またはWebAssemblyをターゲットにできる。一つの隔離メカニズムを選ばない。それらを入れ替えられる抽象を選ぶ。
信頼されていない任意のコードには、Firecracker式のMicroVMがゴールドスタンダードのまま。 未変更のLinuxバイナリに同等の隔離を提供するものは他にない。でも積極的に特化させる——ゲストカーネルを削ぎ落とし、スナップショット復元を使い、Little's Law(L = lambda * W)でサイズを決めた事前ウォームプールを維持する。
制約された計算関数(I/Oなし、スレッドなし)には、OSを排除する。 Dandelionの計算/通信の分割が正しい設計だ。純粋な計算関数にはゲストカーネルは不要だ。syscallも不要だ。ユーザースペースの仮想ファイルシステムを通じて標準インターフェースを提供するカスタムlibcを持つメモリコンテキストで実行する。コールドスタートと密度の改善は無視するには大きすぎる。
syscallフィルタリングには、今cBPFで出荷しても eBPFを計画する。 一時的特化——起動フェーズsyscallを許可するが実行中はブロックする——は本質的に無料の33〜55%の攻撃面削減だ。cBPFからeBPFへの移行ができる方法でフィルタを書く、カーネルサポートが着次第。
プロセス内隔離には、長期的にCHERIに賭ける。 MPKの16キー制限は現実の制約だ。lwCはFreeBSDから抜け出せなかった。CHERIはキー制限なし、ページアライメント要件なし、100マイクロ秒未満のサンドボックス作成でポインタ単位の境界強制を提供する。商用ハードウェアでまだ本番対応ではないが、Morelloの結果はそれに対応するように抽象を設計するには十分に説得力がある。
常にサンドボックスをサンドボックスする。 FirecrackerのJailerパターン——chroot、名前空間、VMM自体の周りの24-syscall許可リスト——はどの隔離ランタイムにもデフォルトであるべきだ。ランタイムにバグがある場合、攻撃者はホストではなく別のサンドボックスに降り立つべきだ。
フィールドはカーネル境界が複数の選択肢の一つとなり、ハードウェアケーパビリティがポインタ粒度でメモリ安全性を強制し、「コールドスタート問題」がリクエストごとにサンドボックスを作成するほど安価にすることで解決される世界に収束している。まだそこにはいない。でもこれら10本の論文を読んで、軌跡は明白だ。
この記事は以下の研究を統合している:zpoline(ATC 2023)、lazypoline(DSN 2024)、K23(Middleware 2025)、Firecracker(NSDI 2020)、Faasm(ATC 2020)、Enclosure(ASPLOS 2021)、Lightweight Contexts(OSDI 2016)、Seccomp-eBPF(arXiv 2023)、SigmaOS(SOSP 2024)、Dandelion(SOSP 2025)。
研究:Akashi。Shimmyサーバーレスサンドボックスプロジェクトの一部。
