web-dev-qa-db-ja.com

システムにrootfsファイルシステムが存在しないのはなぜですか?

Linuxカーネルのドキュメント 主張:

Rootfsはramfs(または有効になっている場合はtmpfs)の特別なインスタンスであり、2.6システムに常に存在します。 rootfsをアンマウントすることはできません…

私がテストしたすべてのLinuxシステム(カーネル> 2.6およびafaikの通常のブート手順(ubuntu 12.04など))では、mountrootfsエントリが表示されません。

ただし、外部の.cpioアーカイブで起動するときに buildroot イメージを使用すると、それが存在します。

rootfsmountエントリがあるのはどのような場合ですか?

4
Georg Schölly
  1. 古いシステムでは、mountが_/proc/mounts_と一致しない場合があります
  2. ほとんどの場合、_/proc/mounts_にrootfsは表示されませんが、マウントされたままです。
  3. Rootfsがまだマウントされていることを証明できますか?

1.古いシステムでは、mountが_/proc/mounts_と一致しない場合があります

_man mount_は次のように述べています。「プログラムmountおよびumountは、従来、ファイル_/etc/mtab_に現在マウントされているファイルシステムのリストを保持していました。」

古いアプローチは、ルートファイルシステムでは実際には機能しません。ルートファイルシステムは、mountではなく、カーネルによってマウントされている可能性があります。したがって、_/_内の_/etc/mtab_のエントリは非常に工夫されている可能性があり、必ずしもカーネルの現在のマウントリストと同期しているとは限りません。

確かにチェックしていませんが、実際には、古いスキームを使用するシステムがmtabを初期化してrootfsの行を表示することはないと思います。 (理論的には、mountrootfsを表示するかどうかは、mtabファイルを最初にインストールしたソフトウェアによって異なります)。

_man mount_続き: "実際のmtabファイルは引き続きサポートされますが、現在のLinuxシステムでは、代わりに/ proc/mountsへのシンボリックリンクにすることをお勧めします。ユーザースペースで維持される通常のmtabファイルは名前空間で確実に機能しないため、コンテナやその他の高度なLinux機能。」

mtabは、Debian7およびUbuntu15.04でシンボリックリンクに変換されます。

1.1出典

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のコードネーム

2.ほとんどの場合、_/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
_

3. rootfsがまだマウントされていることを証明できますか?

悪名高いことに、特権ユーザーとして実行している場合は、単純な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_シーケンスを逆にすることはできません。完全なシーケンスは

  1. 現在の作業ディレクトリ(_/proc/self/cwd_のように)を新しいファイルシステムのマウントポイントに変更します。

    _cd /newmount
    _
  2. 新しいファイルシステムを移動します。つまり、マウントポイントを変更して、ルートディレクトリの一番上に直接配置されるようにします。

    _mount --move . /
    _
  3. 現在のルートディレクトリを(_/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
_

(私はまた、このファイルシステムが空であることを確認しました 予想通り 、そして書き込み可能です)。

3
sourcejedi