pivot_root(2)
旧バージョンで実行可能だった下記サンプルpivot_rootが、現バージョンではpivot_rootシステムコールがEINVALでの不可となっています。
従って、現行バージョンでpivot_rootするには、プロセスのrootをカーネル起動時のmntでなく、mountされているディレクトリをchrootでプロセスのrootとする事でpivot_rootの実行が可能となるようです。
[root@localhost v.north]# mount -t ramfs none /ramdisk
[root@localhost v.north]# mkdir /ramdisk/old-root
[root@localhost v.north]# strace -o babakaka pivot_root /ramdisk/ /ramdisk/old-root/
pivot_root: ルートディレクトリを `/ramdisk/' から `/ramdisk/old-root/' に変更する処理が失敗しました: 無効な引数です
[root@localhost v.north]# cat babakaka | grep "pivot_root("
pivot_root("/ramdisk/", "/ramdisk/old-root/") = -1 EINVAL (Invalid argument)
SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, const char __user *, put_old)
{
struct path new, old, parent_path, root_parent, root;
struct mount *new_mnt, *root_mnt;
int error;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
error = user_path_dir(new_root, &new);
if (error)
goto out0;
error = user_path_dir(put_old, &old);
if (error)
goto out1;
error = security_sb_pivotroot(&old, &new);
if (error)
goto out2;
get_fs_root(current->fs, &root);
error = lock_mount(&old);
if (error)
goto out3;
error = -EINVAL;
new_mnt = real_mount(new.mnt);
root_mnt = real_mount(root.mnt);
if (IS_MNT_SHARED(real_mount(old.mnt)) ||
IS_MNT_SHARED(new_mnt->mnt_parent) ||
IS_MNT_SHARED(root_mnt->mnt_parent))
goto out4;
if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
goto out4;
error = -ENOENT;
if (d_unlinked(new.dentry))
goto out4;
if (d_unlinked(old.dentry))
goto out4;
error = -EBUSY;
if (new.mnt == root.mnt ||
old.mnt == root.mnt)
goto out4; /* loop, on the same file system */
error = -EINVAL;
if (root.mnt->mnt_root != root.dentry)
goto out4; /* not a mountpoint */
if (!mnt_has_parent(root_mnt))
goto out4; /* not attached */
if (new.mnt->mnt_root != new.dentry)
goto out4; /* not a mountpoint */
if (!mnt_has_parent(new_mnt))
goto out4; /* not attached */
/* make sure we can reach put_old from new_root */
if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new))
goto out4;
br_write_lock(&vfsmount_lock);
detach_mnt(new_mnt, &parent_path);
detach_mnt(root_mnt, &root_parent);
attach_mnt(root_mnt, &old);
attach_mnt(new_mnt, &root_parent);
touch_mnt_namespace(current->nsproxy->mnt_ns);
br_write_unlock(&vfsmount_lock);
chroot_fs_refs(&root, &new);
error = 0;
out4:
unlock_mount(&old);
if (!error) {
path_put(&root_parent);
path_put(&parent_path);
}
out3:
path_put(&root);
out2:
path_put(&old);
out1:
path_put(&new);
out0:
return error;
}
以前のバージョンからEINVALエラーに係る以下の条件が追加されています。
if (IS_MNT_SHARED(real_mount(old.mnt)) ||
IS_MNT_SHARED(new_mnt->mnt_parent) ||
IS_MNT_SHARED(root_mnt->mnt_parent))
goto out4;
if (!mnt_has_parent(root_mnt))
goto out4;
備考
MNT_SHAREDはmount後にマウント属性変更での設定で、mountでのMNT_SHAREDは設定できません。従ってサンプルのpivot_rootエラーは、if (!mnt_has_parent(root_mnt))で、プロセスのrootのデバイスが親を有しないシステム起動時のrootデバイス故です。従って、現行バージョンでpivot_rootするには、プロセスのrootをカーネル起動時のmntでなく、mountされているディレクトリをchrootでプロセスのrootとする事でpivot_rootの実行が可能となるようです。





