Dokumentace linuxového jádra tvrdí:
Rootfs je speciální instance ramfs (nebo tmpfs, pokud je povoleno),
který je vždy přítomen v systémech 2.6. Nemůžete odpojit rootfs…
Na všech linuxových systémech, které jsem testoval (kernel> 2.6 a afaik normální zaváděcí procedura, např. ubuntu 12.04), mount
nezobrazuje rootfs
vstup.
Nicméně s bitovou kopií buildroot při spouštění s externím .cpio
archiv, je přítomen.
V jakých případech existuje rootfs
záznam v mount
?
Přijatá odpověď:
- Na starých systémech
mount
nemusí souhlasit s/proc/mounts
- Většinou neuvidíte
rootfs
v/proc/mounts
, ale je stále připojen. - Můžeme dokázat, že rootfs je stále připojen?
1. Na starých systémech mount
nemusí souhlasit s /proc/mounts
man mount
říká:„Programy se mount
a umount
tradičně udržoval seznam aktuálně připojených souborových systémů v souboru /etc/mtab
.“
Starý přístup ve skutečnosti nefunguje pro kořenový souborový systém. Kořenový souborový systém mohl být připojen jádrem, nikoli pomocí mount
. Proto položky pro /
v /etc/mtab
může být docela vymyšlené a nemusí být nutně synchronizované s aktuálním seznamem připojení jádra.
S jistotou jsem to nezkontroloval, ale v praxi si nemyslím, že jakýkoli systém, který používá staré schéma, inicializuje mtab
zobrazit řádek s rootfs
. (Teoreticky, zda mount
zobrazuje rootfs
bude záviset na softwaru, který jako první nainstaloval mtab
soubor).
man mount
pokračuje:„skutečný soubor mtab je stále podporován, ale na současných systémech Linux je lepší z něj udělat symbolický odkaz na /proc/mounts, protože běžný soubor mtab udržovaný v uživatelském prostoru nemůže spolehlivě fungovat s jmennými prostory, kontejnery a dalšími pokročilými Linuxem funkce.“
mtab je v Debianu 7 a Ubuntu 15.04 převeden na symbolický odkaz.
Zdroje 1.1
Debian report #494001 – “debian-installer:/etc/mtab musí být symbolický odkaz na /proc/mounts s linuxem>=2.6.26”
#494001 je vyřešen v sysvinit-2.88dsf-14. Viz závěrečná zpráva ze dne 14. prosince 2011. Změna je zahrnuta v Debianu 7 „Wheezy“, vydaném 4. května 2013. (Používá sysvinit-2.88dsf-41).
Ubuntu odložilo tuto změnu až do sysvinit_2.88dsf-53.2ubuntu1. Tato stránka s protokolem změn ukazuje, že změna zadává „vivid“, což je kódové označení pro Ubuntu 15.04.
2. rootfs
většinou neuvidíte v /proc/mounts
, ale stále je připojen
Od Linuxu v4.17 je tato dokumentace jádra stále aktuální. rootfs je vždy přítomen a nelze jej nikdy odpojit. Ale většinou to nevidíte v /proc/mounts.
Pokud zavedete do shellu initramfs, uvidíte rootfs. Pokud je váš initramfs dracut
, stejně jako ve Fedora Linux, můžete to udělat přidáním volby rd.break
na příkazový řádek jádra. (Například uvnitř zavaděče GRUB).
switch_root:/# grep rootfs /proc/mounts
rootfs / rootfs rw 0 0
Když dracut přepne systém na skutečný kořenový souborový systém, nemůžete již vidět rootfs v /proc/mounts. dracut může použít buď switch_root
nebo systemd
udělat toto. Oba se řídí stejnou posloupností operací, které jsou doporučeny v připojeném kernel doc.
V některých dalších příspěvcích mohou lidé vidět rootfs v /proc/mounts po vypnutí initramfs. Například na Debianu 7:‚Jak mohu zjistit o „rootfs“‘. Myslím, že to musí být proto, že jádro změnilo způsob, jakým zobrazuje /proc/mounts, v určitém okamžiku mezi verzí jádra v Debianu 7 a mým aktuálním jádrem v4.17. Z dalších hledání si myslím, že rootfs je zobrazen na Ubuntu 14.04, ale není zobrazen na Ubuntu 16.04 s jádrem Ubuntu 4.4.0-28-generic.
Související:Linux – Co znamená písmeno „u“ v /dev/urandom?I když nepoužívám initramfs a jádro místo toho připojí kořenový souborový systém, nevidím rootfs v /proc/mounts. To dává smysl, protože se zdá, že kód jádra také sleduje stejnou sekvenci operací.
Operace, která skrývá rootfs, je 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. Můžeme dokázat, že rootfs je stále připojen?
Notoricky známý jednoduchý chroot
lze uniknout, když běžíte jako privilegovaný uživatel. Pokud switch_root
neudělal nic víc než chroot
, mohli bychom to zvrátit a znovu vidět 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
Úplný switch_root
sekvenci nelze touto technikou zvrátit. Celá sekvence ano
-
Změňte aktuální pracovní adresář (jako v
/proc/self/cwd
), do bodu připojení nového souborového systému:cd /newmount
-
Přesuňte nový souborový systém, tj. změňte jeho bod připojení tak, aby seděl přímo nad kořenovým adresářem.
mount --move . /
-
Změňte aktuální kořenový adresář (jako v
/proc/self/root
), aby odpovídal aktuálnímu pracovnímu adresáři.chroot .
Ve výše uvedeném chroot escape jsme byli schopni procházet z kořenového adresáře ext4
souborový systém zpět na rootfs
pomocí ..
, protože ext4
souborový systém byl připojen do podadresáře rootfs
. Metoda escape nefunguje, když je ext4
souborový systém je připojen k rootu adresář rootfs.
Podařilo se mi najít rootfs
pomocí jiné metody. (Přinejmenším jeden důležitý vývojář jádra to považuje za chybu v Linuxu).
http://archive.today/2018.07.22-161140/https://lore.kernel.org/lkml/[e-mail chráněný]/
/* 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);
}
Testováno na Linuxu 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
(Také jsem potvrdil, že tento souborový systém je podle očekávání prázdný a lze do něj zapisovat).