- メモリ安全性とサンドボックス化は相互に独立したセキュリティ概念であり、両方を備えてこそ強固な防御体制になる
- Fil-CはC/C++のメモリ安全な実装であり、Linuxのシステムコールレベルまで安全性を保証し、OpenSSHのようなシステム構成要素でも利用できる
- OpenSSHのseccomp-BPFベースのサンドボックスをFil-Cへ移植する過程では、スレッド生成制限とseccompフィルタ調整が中核的な課題だった
- Fil-Cランタイムのバックグラウンドスレッド管理のために
zlock_runtime_threads() APIが追加され、サンドボックス内でのスレッド動作を制御する
- Fil-Cは
prctl呼び出しをすべてのランタイムスレッドへ同期して適用し、no_new_privsおよびseccompフィルタがプロセス全体に一貫して適用されるよう実装している
メモリ安全性とサンドボックス化の関係
- メモリ安全性とサンドボックス化は異なるセキュリティ層であり、片方だけでは完全な保護を提供しない
- メモリ安全だがサンドボックス化されていない例: Javaプログラムがユーザー入力によってファイルを上書きできる場合
- サンドボックス化されているがメモリ安全でない例: アセンブリで書かれ、権限が制限されたプログラム
- 実際のサンドボックスには、ブローカープロセスとの通信許可などの構造的な抜け穴が存在する
- したがって、メモリ安全性とサンドボックス化を併用することが最善の防御手法である
Fil-CとOpenSSHサンドボックスの統合
- Fil-CはC/C++のメモリ安全な実装であり、Linuxのシステムコールレベルで安全性を維持する
- Fil-Cランタイムは
init、udevdのような低レベルのシステム構成要素でも動作可能
- OpenSSHはFil-C上で正常に動作し、seccomp-BPFサンドボックスを活用する
- OpenSSHはLinuxで次の手段によりサンドボックスを構成する
chrootでファイルシステムアクセスを制限
sshdユーザー/グループで実行
setrlimitでファイルオープン・プロセス生成を制限
- seccomp-BPFフィルタで許可されたシステムコールのみを許可
- Fil-Cは
chrootとユーザー切り替えは基本的にサポートするが、setrlimitとseccomp-BPFはランタイム動作と衝突する可能性があるため追加調整が必要だった
Fil-Cランタイムのスレッド制御
- Fil-Cランタイムはガベージコレクション用のバックグラウンドスレッドを使用し、必要に応じて自動的に停止・再起動する
- OpenSSHの
setrlimitサンドボックスは新しいプロセス生成の禁止を目的とするため、ランタイムのスレッド生成がこれに抵触する可能性がある
- これを解決するため、
<stdfil.h>にzlock_runtime_threads() APIを追加
- ランタイムが必要なスレッドを即座に生成し、その後の自動終了を無効化
- OpenSSHの
ssh_sandbox_child関数でsetrlimitまたはseccomp-BPF呼び出しの前に実行
OpenSSH seccompフィルタの調整
zlock_runtime_threads()適用後も、大半のサンドボックス機能はそのまま動作する
- seccompフィルタでは次の変更が行われた
- 違反時は
SECCOMP_RET_KILL_PROCESSに設定し、Fil-Cバックグラウンドスレッドも含めて終了させる
MAP_NORESERVEを許可リストに追加し、Fil-Cメモリアロケータの使用をサポート
sched_yield呼び出しを許可し、Fil-Cのロック実装で利用できるようにした
- Fil-Cの同期用
futex呼び出しはすでに許可されているため、追加変更は不要だった
Fil-Cのprctl実装方式
- OpenSSHはseccompフィルタのインストール時に2つの
prctl呼び出しを使う
PR_SET_NO_NEW_PRIVSで追加権限の取得を防止
PR_SET_SECCOMP, SECCOMP_MODE_FILTERでフィルタを有効化
- 問題は、
prctlが呼び出したスレッドにのみ適用される点であり、Fil-Cの他のランタイムスレッドがフィルタなしで残る危険がある
- Fil-Cはこれを防ぐため、
filc_runtime_threads_handshake() APIによりすべてのランタイムスレッドへ同期適用する
- 各スレッドが同一の
prctl呼び出しを実行することを保証
- 複数のユーザースレッドが存在する場合はFil-C安全性エラーを発生させ、防御を強化
結論
- メモリ安全性とサンドボックス化の組み合わせが最も強力なセキュリティの組み合わせである
- Fil-CはOpenSSHのseccompベースのサンドボックスを完全に統合しつつ、保護レベルを低下させることなくメモリ安全性を維持する
- Linux環境でFil-Cを活用すれば、システムレベルのセキュリティと言語レベルの安全性を同時に確保できる
1件のコメント
Hacker Newsの意見
なぜ landlock への言及がないのか気になる
C → WASM → Cへとつながる ハイブリッドコンパイル手法 がある
こうするとOSとの相互作用を完全に制御しつつ、WASMのようにメモリアクセスをサンドボックス化しながら、技術的には依然としてCコードのままでいられる
関連資料は RLBox で見られる
メモリを壊すことはできるが、その範囲がサンドボックス内に制限されるだけだ
SECCOMPのようなシステムはあらゆる相互作用ポリシーを細かく定義しなければならず、官僚的 だ
一方Fil-Cは、言語とランタイム自体がプログラムの正しい動作を保証しようとするアプローチを取る
Fil-Cバイナリは通常の実行ファイルなので、SECCOMPのようなサンドボックスと併用することもできる
Linuxがprctlインターフェースを作るのに20年かかったのだから、WASIで似たようなものを見るには10年は待つことになりそうだ
サンドボックス内部でもおかしな実行フローを作れてしまう
Fil-Cの作者は 技術的に興味深い発明 をするのはうまいが、実装検証が十分になされているのかは心配だ
setuidプログラムをFil-Cでコンパイルできると言っていたが、ld.soを修正した部分が危険かもしれない
setuidアプリは環境変数、ファイルディスクリプタ、rlimit、シグナルなどに対して非常に防御的に書かれていなければならない
こうした部分はまだ未完成なので、実際のインフラで使うには リスク がある
それでもコードベースをFil-Cでテストしてみれば、興味深いバグが見つかるかもしれない
ld.soの修正は、libcレイアウトを教える程度の小さな変更だ
setuid関連のgetenvバグもすでにsecure_getenvに修正済みだ
指摘された内容には一部の真実と一部の FUD が混ざっている
Fil-Cではデータレース時にポインタとcapabilityが不一致になる可能性がある
これにより メモリ安全性違反 が発生しうる
作者はこれを否定しているが、Javaと比較するのは不適切だ
技術は素晴らしいが、作者の態度が信頼を損ねている
WASMは サンドボックスであり実行環境 でもあり、使い方によってはある程度のメモリ安全性を確保できる
CをWASMにコンパイルすればバグは依然として存在するが、その影響範囲は制限される
したがってWASMをサンドボックス技術に分類するのは正しいが、実行環境としてさらに多くの可能性がある
モジュールBのバグによってモジュールAのデータを読めてしまう
つまりWASMは軽量なプロセスサンドボックスの代替にすぎない
Cだって「使い方によっては安全だ」と言えてしまうのだから
WASMはランタイム脱出は防げても、内部プログラムのメモリ脱出は防げない
Fil-CとRustの比較を求める声
Fil-Cは既存のCプログラムを 互換性とセキュリティ重視で強化 するのに向いている
Rustは新しいコードベースを作るときに 静的安全性 と 性能 を確保するのに適している
Fil-Cは多少の性能低下はあるが、既存のCコード(ffmpeg、nginx、sudoなど)に有用だ
Rustはマルチスレッドと型システムが強みだ
言語設計の改善よりもメモリ安全性の確保が目的だ
競合はRustというよりD、Nim、Goに近い
Rustは コンパイル時に予防 する
この2つのアプローチは直交しており、RustにもFil-Cスタイルのランタイム検査を追加できる
MicroVM がますます人気を集めている
Fil-Cがこれをどう活用できるのか気になる
このプロジェクトがもっと注目されてほしい
sudoやpolkit のような中核ツールがメモリ安全に配布されるとよい
メモリ安全言語でも サンドボックス活用 がもっと増えてほしい
RustやGoでもOSレベルのサンドボックスがあまり使われていないのは残念だ
ライブラリ単位で設定しにくく、カーネルバージョンやlibc実装に敏感だ
ファイルパスのようなポインタ先の入力はフィルタできず限界がある
そのため通常はアプリケーション単位で直接設定しなければならない
一方Goはランタイムが大きく、Fil-Cのように安全にするのは難しい
Fil-Cが clangのAddress Sanitizer(ASan) と何が違うのか気になる
単にランタイムパニックを出すだけなら、「メモリ安全」と呼ぶのは難しいのではないかという声
一部のバグは検出できない
メモリ周辺に「red zone」を置く方式なので、運がよければ検出される
メモリ安全とは「クラッシュしない」ことではなく、「不正なアクセスが効果を持てない」ことを意味する
完全なVMをサンドボックスとして使ってはいけない理由を問う声
あるプロセスは権限なしで入力をパースし、別のプロセスは高い権限で動作する
2つのプロセスは IPC で通信する
VMを使えばセキュリティは高まるが オーバーヘッド が大きく、GPUやファイルアクセスのような機能も複雑になる
そのため一般にはOSレベルのサンドボックスのほうがすっきりしている
GPUを専用に割り当てる必要があり、QubesもX11フォワーディングでしか接続できず アクセラレーションがない