新しいマウント名前空間にフォークするか、既存の名前空間を入力する場合。
外部マウント名前空間からのファイル記述子を保持することが可能です。 [kdevtmpfs]
などの外部マウント名前空間でプロセスを見つけて/proc/$PID/root
を開くことにより、これを非常に簡単に示すことができます。 (このディレクトリに移動して/bin/pwd
を実行すると、すばらしいエラーメッセージ/usr/bin/pwd: couldn't find directory entry in ‘..’ with matching i-node
が出力されるようで、strace
はgetcwd()
が(unreachable)/
を返したことを示しています)。
新しいマウント名前空間を入力するときに、プロセスが現在のマウント名前空間(現在のディレクトリと現在のルート(chroot))に対して保持する既存の参照がどうなるかを定義してください。
これらの参照のどちらも変更されていない場合、新しいマウント名前空間を入力してもあまり意味がありません。例えば。プロセスのルートがまだ古いマウント名前空間を指している場合、ファイルを開く/path/to/file
は古いマウント名前空間からファイルを開きます。
繰り返しになりますが、CLONENEWNSを使用したclone()の場合(unshare
コマンドなど)とsetns()の場合(nsenter
コマンドなど)の両方を理解したいと思います。
現在の作業ディレクトリとルートの両方が、入力されたマウント名前空間のルートファイルシステムにリセットされます。
たとえば、nsenter -m --target $$
を実行してchroot
をエスケープできることをテストしました。
(リマインダー:chroot
は、まだルートにいるときに簡単にエスケープできます。man chroot
は、これを行うためのよく知られた方法を文書化しています)。
https://elixir.bootlin.com/linux/latest/source/fs/namespace.c?v=4.17#L3507
static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{
struct fs_struct *fs = current->fs;
注:current
は、現在のタスク(現在のスレッド/プロセス)を意味します。
->fs
は、そのタスクのファイルシステムデータになります。これは、同じプロセス内のスレッドであるタスク間で共有されます。例えば。以下に、作業ディレクトリの変更が->fs
の操作であることがわかります。
例えば。作業ディレクトリを変更すると、同じプロセスのすべてのスレッドに影響します。このようなPOSIX互換スレッドは、clone()のCLONE_FSフラグを使用して実装されます。
struct mnt_namespace *mnt_ns = to_mnt_ns(ns), *old_mnt_ns;
struct path root;
int err;
...
/* Find the root */
err = vfs_path_lookup(mnt_ns->root->mnt.mnt_root, &mnt_ns->root->mnt,
"/", LOOKUP_DOWN, &root);
問題の行は次のとおりです。
/* Update the pwd and root */
set_fs_pwd(fs, &root);
set_fs_root(fs, &root);
...
}
...
const struct proc_ns_operations mntns_operations = {
.name = "mnt",
.type = CLONE_NEWNS,
.get = mntns_get,
.put = mntns_put,
.install = mntns_install,
.owner = mntns_owner,
};