Linuxカーネルのドキュメント 主張:
Rootfsはramfs(または有効になっている場合はtmpfs)の特別なインスタンスであり、2.6システムに常に存在します。 rootfsをアンマウントすることはできません…
私がテストしたすべてのLinuxシステム(カーネル> 2.6およびafaikの通常のブート手順(ubuntu 12.04など))では、mount
にrootfs
エントリが表示されません。
ただし、外部の.cpio
アーカイブで起動するときに buildroot イメージを使用すると、それが存在します。
rootfs
にmount
エントリがあるのはどのような場合ですか?
mount
が_/proc/mounts
_と一致しない場合があります/proc/mounts
_にrootfs
は表示されませんが、マウントされたままです。mount
が_/proc/mounts
_と一致しない場合があります_man mount
_は次のように述べています。「プログラムmount
およびumount
は、従来、ファイル_/etc/mtab
_に現在マウントされているファイルシステムのリストを保持していました。」
古いアプローチは、ルートファイルシステムでは実際には機能しません。ルートファイルシステムは、mount
ではなく、カーネルによってマウントされている可能性があります。したがって、_/
_内の_/etc/mtab
_のエントリは非常に工夫されている可能性があり、必ずしもカーネルの現在のマウントリストと同期しているとは限りません。
確かにチェックしていませんが、実際には、古いスキームを使用するシステムがmtab
を初期化してrootfs
の行を表示することはないと思います。 (理論的には、mount
がrootfs
を表示するかどうかは、mtab
ファイルを最初にインストールしたソフトウェアによって異なります)。
_man mount
_続き: "実際のmtabファイルは引き続きサポートされますが、現在のLinuxシステムでは、代わりに/ proc/mountsへのシンボリックリンクにすることをお勧めします。ユーザースペースで維持される通常のmtabファイルは名前空間で確実に機能しないため、コンテナやその他の高度なLinux機能。」
mtabは、Debian7およびUbuntu15.04でシンボリックリンクに変換されます。
Debianレポート #494001- "debian-installer:/ etc/mtabは、Linux> = 2.6.26で/ proc/mountsへのシンボリックリンクである必要があります"
#494001はsysvinit-2.88dsf-14で解決されています。 クロージングメッセージ 、2011年12月14日付けを参照してください。変更はDebian 7 "Wheezy"に含まれています 2013年5月4日にリリース 。 (sysvinit-2.88dsf-41を使用します)。
Ubuntuはこの変更を sysvinit_2.88dsf-53.2ubuntu1 まで延期しました。その変更ログページには、変更が「vivid」と入力されていることが示されています buntu 15.04のコードネーム 。
/proc/mounts
_にrootfs
は表示されませんが、マウントされたままです。Linux v4.17の時点で、このカーネルのドキュメントはまだ最新です。 rootfsは常に存在し、アンマウントすることはできません。しかし、ほとんどの場合、/ proc/mountsでは表示できません。
Initramfsシェルを起動すると、rootfsが表示されます。 FedoraLinuxのようにinitramfsがdracut
の場合、カーネルコマンドラインにオプション_rd.break
_を追加することでこれを行うことができます。 (例:GRUBブートローダー内)。
_switch_root:/# grep rootfs /proc/mounts
rootfs / rootfs rw 0 0
_
Dracutがシステムを実際のルートファイルシステムに切り替えると、/ proc/mountsにrootfsが表示されなくなります。 dracutは、_switch_root
_またはsystemd
のいずれかを使用してこれを行うことができます。これらは両方とも同じ操作シーケンスに従います。これは リンクされたカーネルドキュメント でアドバイスされています。
他のいくつかの投稿では、initramfsから切り替えた後、/ proc/mountsでrootfsを見ることができます。たとえば、Debian 7の場合: ' "rootfs"について知るにはどうすればよいですか '。これは、Debian7のカーネルバージョンと現在のカーネルv4.17の間のある時点で、カーネルが/ proc/mountsの表示方法を変更したためだと思います。さらに検索すると、rootfs is はUbuntu 14.04に表示されますが、 not Ubuntu16.04とUbuntuカーネル4.4.0-28-genericに表示されると思います。
Initramfsを使用せず、代わりにカーネルにルートファイルシステムをマウントさせても、/ proc/mountsにrootfsが表示されません。 カーネルコード も同じ一連の操作に従うように見えるため、これは理にかなっています。
Rootfsを非表示にする操作はchroot
です。
_switch_root:/# cd /sysroot
switch_root:/sysroot# mount --bind /proc proc
switch_root:/sysroot# grep rootfs proc/mounts
rootfs / rootfs rw 0 0
switch_root:/sysroot# chroot .
sh-4.4# cat proc/mounts
/dev/sda3 / ext4 ro,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
_
悪名高いことに、特権ユーザーとして実行している場合は、単純なchroot
をエスケープできます。 _switch_root
_がchroot
以外の何もしなかった場合、それを逆にして、rootfsを再度確認できます。
_sh-4.4# python3
...
>>> import os
>>> os.system('mount --bind / /mnt')
>>> os.system('cat proc/mounts')
/dev/sda3 / ext4 ro,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
/dev/sda3 /mnt ext4 ro,relatime 0 0
>>> os.chroot('/mnt')
>>>
>>> # now the root, "/", is the old "/mnt"...
>>> # but the current directory, ".", is outside the root :-)
>>>
>>> os.system('cat proc/mounts')
/dev/sda3 / ext4 ro,relatime 0 0
>>> os.chdir('..')
>>> os.system('bash')
Shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
Shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
bash-4.4# chroot .
sh-4.4# grep rootfs proc/mounts
rootfs / rootfs rw 0 0
_
ただし、この手法では完全な_switch_root
_シーケンスを逆にすることはできません。完全なシーケンスは
現在の作業ディレクトリ(_/proc/self/cwd
_のように)を新しいファイルシステムのマウントポイントに変更します。
_cd /newmount
_
新しいファイルシステムを移動します。つまり、マウントポイントを変更して、ルートディレクトリの一番上に直接配置されるようにします。
_mount --move . /
_
現在のルートディレクトリを(_/proc/self/root
_のように)現在の作業ディレクトリと一致するように変更します。
_chroot .
_
上記のchrootエスケープでは、_ext4
_ファイルシステムがマウントされているため、_..
_ファイルシステムのルートディレクトリから_ext4
_を使用してrootfs
に戻ることができました。 rootfs
のサブディレクトリ。 _ext4
_ファイルシステムがrootfsのrootディレクトリにマウントされている場合、escapeメソッドは機能しません。
別の方法でrootfs
を見つけることができました。 (少なくとも1人の重要なカーネル開発者はこれをLinuxのバグと考えています)。
http://archive.today/2018.07.22-161140/https://lore.kernel.org/lkml/[email protected]/
_/* CURSED.c - DO NOT RUN THIS PROGRAM INSIDE YOUR MAIN MOUNT NAMESPACE */
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /* open() */
#include <sys/mount.h>
#include <sched.h> /* setns() */
#include <sys/statfs.h>
int main() {
int fd = open("/proc/self/ns/mnt", O_RDONLY);
/* "umount -l /" - lazy unmount everything we can see */
umount2("/", MNT_DETACH);
/* reset root, by re-entering our mount namespace */
setns(fd, CLONE_NEWNS);
/* "stat -f /" - inspect the root */
struct statfs fs;
statfs("/", &fs);
}
_
Linux 4.17.3-200.fc28.x86_64でテスト済み:
_$ make CURSED
cc CURSED.c -o CURSED
$ Sudo unshare -m strace ./CURSED
...
openat(AT_FDCWD, "/proc/self/ns/mnt", O_RDONLY) = 3
umount2("/", MNT_DETACH) = 0
setns(3, CLONE_NEWNS) = 0
statfs("/", {f_type=RAMFS_MAGIC, f_bsize=4096, f_blocks=0, f_bfree=0, f_bavail=0, f_files=0, f_ffree=0, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID}) = 0
^
^ result: rootfs uses ramfs code on this system
_
(私はまた、このファイルシステムが空であることを確認しました 予想通り 、そして書き込み可能です)。