gVisor(ユーザー空間カーネル)
コンテナの脆弱性はホストカーネル直撃になりがち。システムコールをユーザー空間で横取り・再実装するgVisorのSentryなら、性能を落としつつも攻撃面を大きく縮小できます。
- 1.gVisorはSentryというGo製のユーザー空間カーネルがシステムコールを横取りして自前で再実装し、アプリからホストカーネルへの直接到達を遮断する。
- 2.捕捉方式(プラットフォーム)はptrace・systrap・KVMの3種があり、往復コストと隔離強度が異なる。デフォルトはコンテキストスイッチを減らしたsystrap。
- 3.SentryがホストOSに対して発行する呼び出し自体もseccomp-bpfで極小に絞り、Sentryが破られても二段目の壁が残る多層防御になっている。
問題設定:共有カーネルという攻撃面
コンテナは namespace・cgroup・capability を組み合わせた軽量な隔離ですが、コンテナ内のプロセスが発行するシステムコールは最終的にホストの単一カーネルが処理します。カーネルに脆弱性があれば、namespace で見える範囲を絞っていても、そのバグ一つで隔離を突破されます。350を超えるシステムコール実装のどこか一箇所が穴になり得るという意味で、共有カーネルそのものが広い攻撃面です。
gVisor(Google製、ランタイム名は runsc)はこの前提を変えます。VM を新たに起動するのではなく、アプリのシステムコールをホストカーネルに素通りさせず、ユーザー空間で作った別のカーネルに肩代わりさせるという発想です。
Sentry:ユーザー空間に実装されたカーネル
中核は Sentry と呼ぶ、Go で書かれたユーザー空間プロセスです。サンドボックス内のアプリが open や mmap、futex などのシステムコールを呼ぶと、それはホストカーネルへ渡らず Sentry が横取りします。Sentry は200以上のシステムコールを自前で再実装しており、プロセス管理・仮想メモリ・シグナル・ネットワークスタックまで、本来カーネルが担う仕事の大部分をユーザー空間コードとして持っています。ファイルアクセスは Gofer という別プロセスに委譲され、ホストのファイルシステムに直接触れるのは Gofer 側に限定されます。
[通常のコンテナ]
アプリ ──syscall──► ホストカーネル(そのまま到達、広い攻撃面)
[gVisor]
アプリ ──syscall──► Sentry(ユーザー空間カーネル、Go実装)
│ 必要な分だけhostシステムコール
▼
ホストカーネル(seccompで極小に制限)
ポイントは、アプリが何百種のシステムコールを呼んでも、ホストカーネルが実際に受け取るのは Sentry 自身が使う数十種程度に絞られることです。攻撃者はまず Sentry の再実装を破り、さらにその先の狭い窓口を抜けねばならず、二段の壁になります。加えて Sentry は Go 製でメモリ安全性がある程度確保されており、C実装の本物のカーネルに比べてバッファオーバーフロー系の脆弱性クラスが起きにくいという設計上の利点もあります。
Sentry は seccomp のようにシステムコールを間引くだけの仕組みではありません。呼び出しを許可した上で、その意味論(ファイルディスクリプタの管理、ページフォールト処理、シグナル配送順序など)を丸ごと自分の中で再現します。だからこそアプリ側は自分がサンドボックス内にいることに気づかず動作できます。
プラットフォーム:どうやってシステムコールを横取りするか
アプリの実行を止めてシステムコール発行の瞬間を捕まえる方式を、gVisor では「プラットフォーム」と呼びます。方式の違いが性能を大きく左右します。
| 方式 | 捕捉のしくみ | 特徴 |
|---|---|---|
| ptrace | PTRACE_SYSCALLでアプリを都度停止 | 実装は単純だが停止のたびに追加のコンテキストスイッチが入り遅い。非推奨 |
| systrap | seccomp-bpfのTRAPやシグナルを使いアプリ自身に横取りコードを実行させる | ptrace往復を省いた現行デフォルト。仮想化支援なしで動く |
| KVM | Sentryをゲストとして動かし、アプリのsyscall命令をVM exitとして捕捉 | ハードウェア仮想化を借りる分、構成次第で速いがネスト仮想化下では不利になりがち |
ptrace 方式は最初期の実装で、アプリがシステムコールを呼ぶたびにトレーサ(Sentry)へ制御が移り、判定して戻す、という往復が発生します。この往復1回ごとに複数回のコンテキストスイッチが挟まるため、システムコール多発なワークロードで顕著に遅くなります。
systrap 方式はこれを避けるため、seccomp-bpf の SECCOMP_RET_TRAP やシグナルの仕組みを使い、アプリのアドレス空間内に置いた横取りコードでシステムコール命令をその場で捕捉します。ptrace のようにカーネル経由でトレーサへ往復する手間が減るため、2023年以降は既定のプラットフォームになっています。仮想化支援を必要としないため、VM の中や仮想化非対応環境でも動く汎用性があります。
KVM 方式は Sentry 自身をゲストとして VMX non-root で走らせ、アプリのシステムコール命令発行を VM exit として直接 Sentry に引き渡します。ハードウェア仮想化の機構をそのまま利用するため理論上は高速になり得ますが、クラウド環境などですでに1段仮想化されている上でさらに動かす「ネスト仮想化」下では相性が悪く、systrap より遅くなりがちです。このためデフォルトの選択にはなっていません。
性能だけでなく隔離の性質も方式ごとに違います。KVM方式はハードウェア仮想化の壁がSentryとホストの間にもう一枚入るため、Sentry自体が乗っ取られた場合の被害範囲を狭められる可能性があります。ptrace/systrapはあくまでLinuxのプロセス境界とseccompに頼るため、壁の種類が異なる点は把握しておく必要があります。
ホストカーネルへの窓口を seccomp で縛る
Sentry がアプリのシステムコールを肩代わりできても、Sentry 自身は最終的にホスト OS の上で動くプロセスです。メモリ確保やスレッド生成、Gofer との通信などのためにホストカーネルへシステムコールを発行する必要があります。gVisor はここに seccomp-bpf を適用し、Sentry プロセスが呼べるホスト側システムコールをホワイトリストで極端に絞ります。
この結果、防御は二層構造になります。第一層は Sentry によるシステムコールの再実装そのもの(アプリからは巨大な攻撃面である本物のカーネルが見えない)、第二層は Sentry が万一乗っ取られた場合に備えた seccomp フィルタ(Sentry が悪用してもホストに対してできることが限られる)です。片方が破られてももう片方が残るという多層防御の考え方は、コンテナランタイム一般に共通する設計思想でもあります。
性能とセキュリティのトレードオフ
Sentry を経由する構造は、CPU 計算中心のワークロードにはほとんど影響しません。計算はアプリのユーザー空間コードがそのまま実行され、Sentry が介入するのはシステムコール発生時だけだからです。一方で、システムコールやI/Oを高頻度に発行するワークロード(多数の小さなファイル操作を伴うデータベースや、パケット処理が多いネットワークサーバーなど)では、横取りと再実装のオーバーヘッドが積み重なり、素のコンテナに比べて処理時間が伸びやすくなります。
| 観点 | 通常のコンテナ | gVisor |
|---|---|---|
| ホストカーネルへの到達 | システムコールがほぼ直接届く | Sentryが肩代わりし、直接到達は原則なし |
| 攻撃面 | 巨大な共有カーネル全体 | Sentryの再実装コード+seccompで絞ったホスト窓口 |
| CPU計算中心の性能 | ほぼネイティブ | ほぼネイティブ |
| syscall/I/O多発時の性能 | ほぼネイティブ | Sentry経由の分オーバーヘッドが乗りやすい |
| 互換性 | ホストカーネルの実装に準拠 | Sentry未実装のsyscallがあると動作しない場合がある |
互換性の面でも注意が必要です。Sentry は主要なシステムコールを幅広くカバーしていますが、本物のカーネルの全機能を100%再現しているわけではありません。特定のデバイスファイルや稀な ioctl、一部の高度なネットワーク機能などで未実装の呼び出しに当たると、アプリが期待通り動かない、あるいはエラーになることがあります。採用前には対象アプリが実際に使うシステムコールの範囲を確認する価値があります。
gVisorは攻撃面を「巨大なホストカーネル全体」から「Sentryの再実装コードの正しさ」へ縮小しますが、ゼロにするわけではありません。Sentry自体にメモリ安全でない実装ミスがあれば、そこが新たな脆弱性になります。seccompによるホスト側の絞り込みも「多層防御の一枚」であって単独で万能ではなく、他の隔離機構と組み合わせる前提の設計です。
まとめ
gVisor は VM を使わず、Sentry というユーザー空間カーネルにシステムコールを横取り・再実装させることで、アプリからホストカーネルへの直接到達を断ちます。捕捉方式は ptrace(低速・非推奨)、systrap(現行デフォルト、往復コスト削減)、KVM(仮想化支援を借りるが構成次第)の3種類があり、性能と隔離強度のバランスが異なります。Sentry がホストに対して発行する呼び出し自体も seccomp-bpf で極小に絞ることで、Sentry が破られても被害を局所化する二段構えです。トレードオフとしては、CPU計算中心なら影響は小さい一方、システムコールやI/Oが多いワークロードでは横取りのオーバーヘッドが顕在化し、Sentry未実装の呼び出しに依存するアプリは動作しない場合もあります。
OS Article
gVisor(ユーザー空間カーネル)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
gVisor
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
捕捉方式(プラットフォーム)はptrace・systrap・KVMの3種があり、往復コストと隔離強度が異なる。デフォルトはコンテキストスイッチを減らしたsystrap。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「gVisor / セキュリティ」に近いか確認する。
- 強みである「gVisorはSentryというGo製のユーザー空間カーネルがシステムコールを横取りして自前で再実装し、アプリからホストカーネルへの直接到達を遮断する。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。