# PID Namespace {{#include ../../../../banners/hacktricks-training.md}} ## 基本情報 PID (プロセス識別子) ネームスペースは、Linux カーネルの機能であり、プロセスの隔離を提供します。これにより、一群のプロセスが他のネームスペースの PID とは別の一意の PID のセットを持つことができます。これは、プロセスの隔離がセキュリティとリソース管理に不可欠なコンテナ化に特に役立ちます。 新しい PID ネームスペースが作成されると、そのネームスペース内の最初のプロセスには PID 1 が割り当てられます。このプロセスは新しいネームスペースの「init」プロセスとなり、そのネームスペース内の他のプロセスを管理する責任を負います。ネームスペース内で作成される各後続プロセスは、そのネームスペース内で一意の PID を持ち、これらの PID は他のネームスペースの PID とは独立しています。 PID ネームスペース内のプロセスの視点から見ると、同じネームスペース内の他のプロセスのみを見ることができます。他のネームスペースのプロセスを認識せず、従来のプロセス管理ツール(例: `kill`, `wait` など)を使用して相互作用することはできません。これにより、プロセスが互いに干渉するのを防ぐための隔離レベルが提供されます。 ### 仕組み: 1. 新しいプロセスが作成されると(例: `clone()` システムコールを使用)、プロセスは新しいまたは既存の PID ネームスペースに割り当てられます。**新しいネームスペースが作成されると、プロセスはそのネームスペースの「init」プロセスになります**。 2. **カーネル**は、新しいネームスペース内の PID と親ネームスペース内の対応する PID との**マッピングを維持します**(つまり、新しいネームスペースが作成されたネームスペース)。このマッピングは、**カーネルが必要に応じて PID を変換できるようにします**。たとえば、異なるネームスペースのプロセス間で信号を送信する際などです。 3. **PID ネームスペース内のプロセスは、同じネームスペース内の他のプロセスのみを見たり相互作用したりできます**。彼らは他のネームスペースのプロセスを認識せず、彼らの PID はそのネームスペース内で一意です。 4. **PID ネームスペースが破棄されると**(例: ネームスペースの「init」プロセスが終了すると)、**そのネームスペース内のすべてのプロセスが終了します**。これにより、ネームスペースに関連するすべてのリソースが適切にクリーンアップされます。 ## ラボ: ### 異なるネームスペースを作成する #### CLI ```bash sudo unshare -pf --mount-proc /bin/bash ```
エラー: bash: fork: メモリを割り当てできません `unshare`が`-f`オプションなしで実行されると、Linuxが新しいPID(プロセスID)名前空間を扱う方法によりエラーが発生します。以下に重要な詳細と解決策を示します。 1. **問題の説明**: - Linuxカーネルは、プロセスが`unshare`システムコールを使用して新しい名前空間を作成することを許可します。しかし、新しいPID名前空間の作成を開始するプロセス(「unshare」プロセスと呼ばれる)は、新しい名前空間に入ることはなく、その子プロセスのみが入ります。 - `%unshare -p /bin/bash%`を実行すると、`unshare`と同じプロセスで`/bin/bash`が開始されます。その結果、`/bin/bash`とその子プロセスは元のPID名前空間に存在します。 - 新しい名前空間内の`/bin/bash`の最初の子プロセスはPID 1になります。このプロセスが終了すると、他にプロセスがない場合、名前空間のクリーンアップがトリガーされます。PID 1は孤児プロセスを引き取る特別な役割を持っているためです。Linuxカーネルはその名前空間でのPID割り当てを無効にします。 2. **結果**: - 新しい名前空間内でPID 1が終了すると、`PIDNS_HASH_ADDING`フラグがクリーニングされます。これにより、新しいプロセスを作成する際に`alloc_pid`関数が新しいPIDを割り当てることに失敗し、「メモリを割り当てできません」というエラーが発生します。 3. **解決策**: - この問題は、`unshare`に`-f`オプションを使用することで解決できます。このオプションにより、`unshare`は新しいPID名前空間を作成した後に新しいプロセスをフォークします。 - `%unshare -fp /bin/bash%`を実行すると、`unshare`コマンド自体が新しい名前空間内でPID 1になります。これにより、`/bin/bash`とその子プロセスはこの新しい名前空間内に安全に収容され、PID 1の早期終了を防ぎ、通常のPID割り当てを可能にします。 `unshare`が`-f`フラグで実行されることを確保することで、新しいPID名前空間が正しく維持され、`/bin/bash`とそのサブプロセスがメモリ割り当てエラーに遭遇することなく動作できるようになります。
新しいインスタンスの`/proc`ファイルシステムをマウントすることで、`--mount-proc`パラメータを使用すると、新しいマウント名前空間がその名前空間に特有のプロセス情報の**正確で孤立したビュー**を持つことが保証されます。 #### Docker ```bash docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` ### プロセスがどの名前空間にあるかを確認する ```bash ls -l /proc/self/ns/pid lrwxrwxrwx 1 root root 0 Apr 3 18:45 /proc/self/ns/pid -> 'pid:[4026532412]' ``` ### すべてのPID名前空間を見つける ```bash sudo find /proc -maxdepth 3 -type l -name pid -exec readlink {} \; 2>/dev/null | sort -u ``` 初期(デフォルト)のPID名前空間からのrootユーザーは、すべてのプロセスを見ることができます。新しいPID名前空間内のプロセスも含まれています。これが、すべてのPID名前空間を見ることができる理由です。 ### PID名前空間に入る ```bash nsenter -t TARGET_PID --pid /bin/bash ``` PID ネームスペースにデフォルトのネームスペースから入ると、すべてのプロセスを見ることができます。そして、その PID ns のプロセスは新しい bash を PID ns で見ることができます。 また、**root でない限り、他のプロセスの PID ネームスペースに入ることはできません**。そして、**ディスクリプタ**がそれを指していない限り、他のネームスペースに**入ることはできません**(例えば `/proc/self/ns/pid` のように)。 ## References - [https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory](https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory) {{#include ../../../../banners/hacktricks-training.md}}