linux:kernel:namespace:user_namespace

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン 前のリビジョン
次のリビジョン
前のリビジョン
linux:kernel:namespace:user_namespace [2013/09/01 14:26] – [マッピングファイルを書くルール] tenforwardlinux:kernel:namespace:user_namespace [2013/09/03 16:46] (現在) – [ユーザとグループの ID のマッピングを眺める] tenforward
行 127: 行 127:
     $ ./userns_child_exec -U -M '0 1000 1' -G '0 1000 1' bash     $ ./userns_child_exec -U -M '0 1000 1' -G '0 1000 1' bash
 </code> </code>
 +
 +今回は,マッピングファイルの更新が成功し,シェルが期待するユーザ ID,グループ ID,ケーパビリティを持っているのがわかる.
 +
 +<code>
 +    $ id -u
 +    0
 +    $ id -g
 +    0
 +    $ cat /proc/$$/status | egrep 'Cap(Inh|Prm|Eff)'
 +    CapInh: 0000000000000000
 +    CapPrm: 0000001fffffffff
 +    CapEff: 0000001fffffffff
 +</code>
 +
 +userns_child_exec プログラムの実装には微妙な点が少し存在する.まず,親プロセス (すなわち clone() を呼び出した側) も新しい子プロセスも,新しいユーザ名前空間の uid/gid のマッピングを更新可能であることである.しかし,先に述べたルールにより,子プロセスは自身の実効ユーザ ID だけをマップするマッピングを定義できる.もし,任意の子供内でのユーザ ID,グループ ID のマッピングを定義したい場合,定義は親プロセス側で行わなければならない.その上,親プロセスは適切なケーパビリティを持っていなければならない.具体的には CAP_SETUID, CAP_SETGID,  (そして親プロセスはマッピングファイルを開くのに必要なパーミッションを持っていることを保証するために) CAP_DAC_OVERRIDE である.
 +
 +その上に,親は子供が execve() を呼ぶ前にマッピングファイルを確実に更新する必要がある (でなければ,子供が execve() の間にケーパビリティを失うという,まさに前述のような問題が生じる).確実に実行するために,2 つのプロセスは必要な同期を取るためパイプを採用している.プログラムのソースコードのコメントに詳細な説明がある.
 +
 +===== ユーザとグループの ID のマッピングを眺める =====
 +
 +今までの所の例で /proc///PID///uid_map と /proc///PID///gid ファイルをマッピングを定義するために使う事を示した.これらのファイルはプロセスが使用しているマッピングを見るのに使う事もできる.これらのファイルに書き込む時と同様に,2 つ目の値 (ID-outside-ns) は親のユーザ名前空間に関する定義がなされている.もしファイルを開いているプロセスが異なるユーザ名前空間にいる場合,ID-outside-ns がファイルを開いているユーザ名前空間に関する定義となる.
 +
 +シェルを実行する 2 つのユーザ名前空間を作成し,名前空間内のプロセスの uid_map ファイルを調べる事で,これを示す事ができる.シェルを実行する新しいユーザ名前空間を作成して,始めよう.
 +
 +<code>
 +    $ id -u            # Display effective user ID
 +    1000
 +    $ ./userns_child_exec -U -M '0 1000 1' -G '0 1000 1' bash
 +    $ echo $$          # Show shell's PID for later reference
 +    2465
 +    $ cat /proc/2465/uid_map
 +                   1000          1
 +    $ id -u            # Mapping gives this process an effective user ID of 0
 +    0
 +</code>
 +
 +ここで別のターミナルウィンドウに移り,異なるユーザとグループのマッピングを持つ兄弟となるユーザ名前空間を作る.
 +
 +<code>
 +    $ ./userns_child_exec -U -M '200 1000 1' -G '200 1000 1' bash
 +    $ cat /proc/self/uid_map
 +           200       1000          1
 +    $ id -u            # Mapping gives this process an effective user ID of 200
 +    200
 +    $ echo $$          # Show shell's PID for later reference
 +    2535
 +</code>
 +
 +2 つ目のユーザ名前空間のシェルを実行している 2 つ目のターミナルウィンドウで,他のユーザ名前空間内のプロセスのユーザ ID のマッピングを見よう.
 +
 +<code>
 +    $ cat /proc/2465/uid_map
 +                    200          1
 +</code>
 +
 +このコマンドの出力は,他のユーザ名前空間内でのユーザ ID 0 が,自分の名前空間内ではユーザ ID 200 にマッピングされていることを示している.同じコマンドが他のユーザ名前空間内で実行されると,異なる出力を生成していることに注意すること.これは,ファイルから読み込みを行っているプロセスの属するユーザ名前空間に従って,カーネルが ID-outside-ns の値を生成しているからである.
 +
 +もし,最初のターミナルウィンドウに戻って,2 つ目のユーザ名前空間内のプロセスに対するマッピングファイルを表示したとすると,以下のような出力が見られるだろう.
 +
 +<code>
 +    $ cat /proc/2535/uid_map
 +           200          0          1
 +</code>
 +
 +再び,ここでの出力は 2 つ目のユーザ名前空間で実行した時の同じコマンドと異なる.これは ID-outside-ns の値はファイルから読み込みを行っているプロセスのユーザ名前空間に従って生成されているからである.もちろん,初期の名前空間では,最初のユーザ名前空間のユーザ ID 0 と,2 つ目の名前空間のユーザ ID 200 は,両方ともユーザ ID 1000 にマッピングされている.これを,初期の名前空間で実行する 3 つ目のシェルウィンドウで以下のコマンドを実行して調べてみよう.
 +
 +<code>
 +    $ cat /proc/2465/uid_map
 +                   1000          1
 +    $ cat /proc/2535/uid_map
 +           200       1000          1
 +</code>
 +
 +===== 最後に =====
 +
 +この記事では,ユーザ名前空間の基礎を見てきた.ユーザ名前空間の作成,ユーザとグループ ID のマッピングファイルの使用,ユーザ名前空間とケーパビリティの関係である.
 +
 +[[http://lwn.net/Articles/528078/|先の記事]]で述べたように,ユーザ名前空間実装の動機の一つは,元は root ユーザに限られていた機能へのアクセスを非 root アプリケーションに与える事である.伝統的な UNIX システムでは,様々な機能は,非特権ユーザが特権プログラムの実行環境の操作するのを防ぐために root ユーザに制限されていた.期待しない,望まない方法でこれらのプログラムの動きが影響を受ける可能性があったためである.
 +
 +ユーザ名前空間は,(名前空間外では特権を持たない) プロセスが,その名前空間に特権の範囲を制限すると同時に root 特権を持てるようにする.その結果,プロセスはシステム全体の特権プログラムの実行環境の操作はできない.これらの root 特権を有意義に使うために,他のタイプの名前空間と同時にユーザ名前空間を同時に使う必要がある.このトピックはこのシリーズの次の記事の主題を形作る.
  
  • linux/kernel/namespace/user_namespace.1378045603.txt.gz
  • 最終更新: 2013/09/01 14:26
  • by tenforward