Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reproducible Containers (ASPLOS'20)

Reproducible Containers (ASPLOS'20)

ゼミ資料 浅田睦葉 20251110

Avatar for Mutsuha Asada

Mutsuha Asada

November 10, 2025
Tweet

More Decks by Mutsuha Asada

Other Decks in Technology

Transcript

  1. 4 書誌情報 ・タイトル  ・Reproducible Containers ・著者  ・Omar S. Navarro Leija,

    Kelly Shiptoski, Ryan G. Scott, Baojun Wang,   Nicholas Renner, Ryan R. Newton, Joseph Devietti ・会議  ・ASPLOS’20  ・The International Conference on Architectural Support for Programming   Languages and Operating Systems 2020 ・URL: https://dl.acm.org/doi/10.1145/3373376.3378519
  2. 11 再現可能コンテナ ・本研究の目標  ・再現可能なコンテナ(reproducible container)を提供すること ・初期のファイルシステム状態とそこから実行されるプログラムにより定義される ・コンテナ内で実行されるプログラムは以下を実行できる  ・任意のx86命令  ・Linuxシステムコール  ・ただし、すべての呼び出しを必ず成功させることは保証しない

    ・コンテナ内で実行されるコードは以下の範囲で相互作用できる  ・自身のファイルシステム  ・コンテナ内で並行して動作する他のプログラム ・将来的には再現性が保証される範囲で外部とのやり取りを許可する方向性  ・ハッシュ値が既知のファイルのダウンロード(Nixにおけるfetchurl)
  3. 13 再現性の構成要素: 決定性 ・同一のマシン上では、すべてのread操作が毎回同じ値を返すという性質を  データフロー決定性と呼ぶ  ・この性質により、時刻や明示的な乱数などの非再現要因が隠蔽される  ・つまり、gettimeofday() や getrandom() は呼べるが、

      DetTraceが固定した値を返すようにする ・決定性が成り立つと、以下のような性質が得られる  ・全てのプロセスが終了した後のファイルシステムの状態が常に同一  ・標準出力、標準エラー出力に出力されるメッセージも常に同一 ・厳密には決定化ができない外部要因が存在するため準決定性(quasi-determinism)  ・たとえば、ディスク容量の枯渇 ・同一の実行を2回行った時、データフロー決定的である or クラッシュ
  4. 18 システムコールの監視と対処 ・Linuxの全てのシステムコールは ptrace で観察できる  ・したがって、クリティカルな = 検出不可能なシステムコールは存在しない ・非再現性の原因となるシステムコールの例  ・時刻系(gettimeofday)

    、乱数系、シグナル、タイマ、ファイルメタデータなど ・対処  ・システムコールをラップしたり代替手段に置き換えたりして決定的にする   ・time() の戻り値を固定値にする  ・システムコールをnopに変換する  ・非サポート扱いとして、再現可能な一貫したエラーを発生させる
  5. 19 x86-64命令における非再現性 ・x86-64命令セットには多数の非再現的命令が存在する ・特権命令  ・非再現的だが、ユーザ空間コンテナで実行されると例外が投げられるので   DetTraceの観点では問題ではない(ので省略) ・rdrand / rdseed  ・ハードウェアエントロピー源からランダムビットを返す命令

     ・ハイパーバイザからは捕捉できるがring 0レベルでは捕捉できない  → cpuidで存在しないと報告してプログラムに使わせない ・rdpmc  ・パフォーマンスカウンタを読み取る命令  → ユーザ空間からも実行できる場合があるが、カーネル設定によりトラップできる
  6. 20 TSX命令の非再現性 ・調査の中で、x86-64命令で明確にクリティカルな命令群を特定した ・TSX: Transactional Synchronization Extensions 命令群  ・複数スレッドが同じメモリを扱う際には、ロックで排他制御を行う  ・しかし、ロックは待ち時間が発生するため性能が低下する

     →ロックを取らずに全部成功 or 全部失敗のどちらかになるようにメモリ操作を行う   ・もし衝突したらやり直す   ・高速に並行実行できる ・トランザクションのabortは観測不能な要因で起こる  ・CPU内部のタイミング、割り込み、キャッシュ状態、...  ・さらに、xbeginでアボートハンドラ(abortすると実行される)を登録できる   → 本質的に決定的に制御できない
  7. 23 設計 ・DetTraceは標準的なLinuxのコンテナ技術を利用する  ・namespace: UIDやPIDなどを隔離する  ・bind mount: 必要なファイルやディレクトリをコンテナに安全に見せる  ・chroot: コンテナ内のファイルシステムを限定する

    ・さらに、ptraceで他のプロセスを監視して、全てのシステムコールを監視する → 環境を隔離し、再現性を壊す動作を再現可能な  形に書き換えるか、禁止する ・ここからは具体的な要因に対する処理を説明
  8. 25 ② OSが生成する乱数 ・Linuxのユーザプロセスは以下の手段で乱数を取得できる  ・① getrandomシステムコール  ・② /dev/random、/dev/urandomのread ・① getrandom()

    のインターセプト  ・PTRACE_SYSCALLをフックして、システムコール番号が__NR_getrandomなら   DetTraceがカーネルに渡さず、自前の擬似乱数生成器で乱数を生成  ・トレースしたプロセスのメモリに乱数を書き込み、成功扱いで実行を再開 ・② /dev/random, /dev/urandom  ・起動時に独自の /dev/random, /dev/urandomを名前付きパイプとして準備  ・DetTraceは別スレッドで擬似乱数を定期的に書き込む
  9. 26 ③ 時刻とクロック ・Linuxのユーザプロセスは以下の手段で現在時刻を取得できる (実行の度に変化)  ・gettimeofday(), clock_gettime(), time() ・DetTraceでは時間をユーザプロセスが時刻取得関数を呼び出した回数と定義する  ・この定義は時刻の単調増加性、再現性、相対的順序を保つ

    ・Linuxでは性能向上のため、gettimeofday() などをシステムコールを呼ばずに  ユーザ空間で直接実行される(vDSOメカニズム)  ・しかし、これはカーネルを通過しないためptraceで呼び出しを捕捉できない  ・LD_PRELOADで上書きすれば良いように思えるが、静的リンクされたバイナリに   効果が無く、プロセスがgetauxval()を使ってvDSOを呼ぶことがある   ・実際に、libcの mkstemp() はvDSOを直接呼び出す ・そこで、プロセスが新しいプログラムを起動した直後に、そのプロセス空間にある  vDSOライブラリを上書きして独自実装を挿入し、syscallを呼び出すようにする
  10. 29 ⑤ ファイルとディレクトリ ・chrootでコンテナ内のプログラムからホストのファイルが見えないようにする ・UID/GID, パーミッションなどのメタデータを入力の一部とみなす  ・コンテナ内で現在のユーザをroot(UID 0)にマップし、それ以外を   nobody/nogroupにマップする ・ディレクトリ内容の取得(getdents())は並び順がファイルシステム依存

     ・DetTraceは名前順にソートしてから返す ・read/writeは要求したバイト数全てを処理しないことがある  ・足りなかった場合は再試行して、プログラムからは1度で全て読めたように見せる  ・read syscallを捕捉 → 部分読み取りであればプログラムカウンタを1つ戻して   再実行し、引数を調整して続きを読む ・ファイル/ディレクトリの一意のIDであるinodeがOSによって再利用される  ・DetTraceがファイルごとに独自の仮想inodeテーブルを管理して再利用しない ・ファイルタイムスタンプは、atime/ctimeを0に固定、mtimeは仮想時刻を割り当て
  11. 31 ⑦ スレッド ・Linuxではスレッドも実装上は軽量プロセスとして扱われる  → ptraceでプロセスと同様の方法で制御できる ・DetTraceでは同じプロセス内の異なるスレッドを順番に実行するように変更する  → 共有メモリへのアクセス順が常に同じになる  →

    競合(race condition)が発生しない  → 何回実行しても、同じ順序で同じ値が読み書きされる ・スレッド間の排他制御にはfutex(fast userspace mutex)が利用される  ・waitが呼ばれるとBlocked queueに入れて停止させる  ・wakeが呼ばれると他のスレッドが再開可能になる  → これによりfutexベースのロックも決定的に動作させることができる