Wie verwende ich OverlayFS zum Schutz des Root-Dateisystems?

8

Wie verwende ich OverlayFS richtig, um mein Root-Dateisystem zu schützen?

Ich habe ein eingebettetes System, das von einer SD-Karte startet und ausgeführt wird. Da es zu einem plötzlichen Stromausfall kommt, möchte ich das Root-Dateisystem schützen. OverlayFS scheint die einfachste Lösung zu sein, aber die Beispiele, die ich finde, betreffen normalerweise nicht das Root-Dateisystem und / oder verwenden ein tmpfs, was für mich nicht gut ist, da ich sehr wenig Speicher habe.

Ich verwende Linux Kernel 4.4.0 mit CONFIG_OVERLAY_FS=yaktiviert. Mein Dateisystem ist xenial-base-armhf.tar.gzund ich habe getan apt install -y overlayroot.

Meine SD-Karte sieht aus wie:

# fdisk -l /dev/mmcblk1
Disk /dev/mmcblk1: 29 GiB, 31104958464 bytes, 60751872 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7f56a0ab

Device         Boot    Start      End  Sectors  Size Id Type
/dev/mmcblk1p1 *        2048  1050623  1048576  512M  c W95 FAT32 (LBA)
/dev/mmcblk1p2       1050624  1052671     2048    1M da Non-FS data
/dev/mmcblk1p3       1052672  7344127  6291456    3G 83 Linux
/dev/mmcblk1p4       7344128 60751871 53407744 25.5G  5 Extended
/dev/mmcblk1p5       7346176 13637631  6291456    3G 83 Linux
/dev/mmcblk1p6      13639680 60751871 47112192 22.5G 83 Linux

Vor dem Erstellen des OverlayFS wird alles wie folgt bereitgestellt:

# mount
/dev/mmcblk1p3 on / type ext4 (rw,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=170440k,nr_inodes=42610,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-    cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=35752k,mode=700)
/dev/mmcblk1p6 on /opt type ext4 (rw,noatime,data=ordered)
/dev/mmcblk1p5 on /overlay type ext4 (rw,noatime,data=ordered)

Mein Plan war es, /dev/mmcblk1p5als Overlay-Dateisystem zu verwenden, das bei gemountet ist /overlay.

# tree /overlay
/overlay
├── lost+found
├── root-fs
└── work

Entweder mache ich etwas falsch oder ich habe ein Konfigurationsproblem, weil:

# mount -t overlay overlay -o lowerdir=/,upperdir=/overlay/root-fs,workdir=/overlay/work /
# mount
/dev/mmcblk1p3 on / type ext4 (rw,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=170440k,nr_inodes=42610,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=35752k,mode=700)
/dev/mmcblk1p6 on /opt type ext4 (rw,noatime,data=ordered)
/dev/mmcblk1p5 on /overlay type ext4 (rw,noatime,data=ordered)
overlay on / type overlay (rw,relatime,lowerdir=/,upperdir=/overlay/root-fs,workdir=/overlay/work)

Sieht so aus, als hätte es funktioniert, aber wenn ich eine Datei erstelle, wie:

# touch /root/test_file_write

Dann ausschalten und auf die SD-Karte in meinem Desktop schauen, sehe ich /dev/mmcblk1p3/root/test_file_writenicht, was ich erwartet hatte /dev/mmcblk1p5/root-fs/root/test_file_write.

Sollte das funktionieren?

proximal
quelle
Leider ist das schreibgeschützte Mounten von / dev / mmcblk1p3 nicht einfach. mount -o remount,ro /kehrt zurück mount: / is busy, und der Versuch, das System schreibgeschützt zu starten, führt zu vielen Fehlern. Es ist mir noch nicht gelungen, aber ich werde es weiter versuchen.
nahe
Ich habe alles mit / getötet und erfolgreich schreibgeschützt wieder montiert. Nun, touch /root/test_file_writekehrt zurück touch: cannot touch '/root/test_file_write': Read-only file system, also funktioniert das Overlay eindeutig nicht ... aber warum?
nahe
Funktioniert es in einem anderen Nicht- / Verzeichnis wie diesem:mkdir /tmp/{root,overlay,work}; touch /tmp/root/lowerfile; mount -t overlay overlay -o lowerdir=/tmp/root,upperdir=/tmp/overlay,workdir=/tmp/work /tmp/root/; touch /tmp/root/upperfile; umount /tmp/root
Rudimeier
Ja das funktioniert Ich ende mit /tmp/overlay/upperfileund /tmp/overlay/root/lowerfile.
nahe
1
Leider habe ich noch keine Lösung gefunden. Es scheint, dass der erwartete Ansatz darin besteht, dies in einem initramfs zu erledigen (genau das macht das apt-Paket overlayrootfs). Ich verwende kein Initramfs und möchte nicht starten. Im Moment verfolge ich den alten Ansatz und verwende ein separates Root-Verzeichnis (aka /), / var und / opt-Verzeichnisse, wobei ich rw selbst einschränke.
nahe

Antworten:

5

Eine Lösung könnte darin bestehen, ein initramfs zu verwenden, um die rootfs mit Overlays zu mounten.

Sie können sehen, wie es auf dem Raspberry Pi gemacht wird

oder, falls nicht ein ARM - Gerät, bei dem overlayrootUbuntu Paket

Mathieu Maret
quelle
Obwohl nicht in der ursprünglichen Frage, habe ich derzeit kein Initramfs und suchte nach einer Lösung, ohne dass ich eines verwenden muss.
nahe
3

Diese Antwort basiert auf meiner eigenen Erfahrung, jedoch nicht mit eingebetteten Geräten. Vielleicht ist es für andere nützlich, die über dieses Setup stolpern - Sie sollten es an Ihre spezifischen Umstände anpassen oder zumindest hoffentlich ein oder zwei Dinge daraus lernen.

Eine einfache Methode besteht darin, den Ort zu entführen, an dem das Root-Dateisystem bereitgestellt wird (in initramfs, andernfalls den initProzess zu entführen ), das Overlay dort bereitzustellen und dann wie gewohnt fortzufahren. Wenn Sie es ohne initramfs bereitstellen, vergessen Sie nicht, alle virtuellen Dateisysteme (z. B. /procund /sys) in Ihrem Skript zu verschieben, bevor Sie die Steuerung an das normale übergeben init.

Wenn Sie kein Initramfs möchten, sollte die verknüpfte Lösung von Mathieu Maret funktionieren, wie es in Himbeeren gemacht wird. Grundsätzlich überschreiben Sie den initProzess / das Skript mit Ihrem eigenen über eine Befehlszeile zum Kernel. Angenommen, Sie erstellen das Skript im Root-Dateisystem unter /sbin/init-overlayund fügen dann die init=/sbin/init-overlayzu den Kernel-Boot-Parametern der Konfiguration Ihres Bootloaders hinzu.

Das init-overlaySkript kann alles tun, bevor es die Kontrolle übergibt init. In diesem Fall wird das Overlay in einem anderen Verzeichnis und dann chrootin diesem Verzeichnis bereitgestellt .


Eine Möglichkeit, dies mit initramfs zu tun, besteht darin, das /initSkript innerhalb des initramfs nach dem Punkt, an dem es das Root-Dateisystem bereitstellt, einfach zu entführen . Angenommen, Sie möchten einen Overlay-Stamm, aber auch Zugriff auf die ursprünglichen Einhängepunkte an /run/rootfs/round /run/rootfs/rw(der erste ist der schreibgeschützte Stamm, der zweite sind die vorgenommenen Änderungen upperdir), nachdem das System betriebsbereit ist . Ich gehe auch davon aus, dass das Laufwerk, das Ihr System startet, eine root.squashfsDatei enthält, die das schreibgeschützte Root-Dateisystem enthält, und dass Sie es bereitstellen möchten. Angenommen, Sie möchten auch /media/drivenach der Inbetriebnahme des Systems auf dieses Laufwerk zugreifen .

Der Grund, warum wir das initramfs-Skript entführen, ist, dass dies uns mehr Flexibilität im Prozess bietet als die Verwendung einiger vorgefertigter Parameter, die ohnehin Standard-Skriptbefehle ausführen. Sie müssen also die Boot-Konfiguration bearbeiten, um dem Kernel die Information zu übergeben, dass das "Root" -Dateisystem tatsächlich dasjenige root.squashfsist, in dem es gefunden wird, da wir es später bereitstellen werden.

Ein typischer Befehl syslinux.cfgauf einer VFAT-Partition wäre (ändern Sie die UUID, falls erforderlich):

label linux
    linux vmlinuz
    append root=UUID=ABCD-1234 rootfstype=vfat rootflags=ro,umask=022,quiet ro quiet splash
    initrd initrd.img

Dies setzt voraus, dass Sie das root.squashfsauf der VFAT-Partition platzieren, was möglicherweise nicht ideal ist (was Sie als root = oben angeben müssen, ist die Partition oder das Dateisystem, das das root.squashfsoder ein ähnliches enthält , z. B. das echte Root-Dateisystem, wenn Sie dies nicht möchten es komprimiert). Ich erkläre es jedoch unter der Annahme, dass Sie es auf der Boot-Partition selbst platzieren. Ich weiß nicht, welche Art von eingebettetem System Sie verwenden, daher müssen Sie hier Ihr eigenes Urteilsvermögen verwenden.

Zuerst müssen Sie die initramfs irgendwo in / tmp extrahieren, damit Sie das /initSkript ändern können . Vergessen Sie nicht, dies als root(Superuser) zu tun , um das Eigentum ordnungsgemäß zu behalten, bevor wir es zurückpacken. Sie können das Ganze wahrscheinlich skripten, nachdem Sie verstanden haben, wie es gemacht werden kann. Zum Beispiel entpacken Sie es /tmp/initramfsfür Änderungen:

mkdir /tmp/initramfs 2>/dev/null; (cd /tmp/initramfs && zcat /initrd.img | sudo cpio -idmv)

Jetzt müssen wir herausfinden, wo das Standardskript das Stammverzeichnis bereitstellt. Suchen Sie nach so etwas in /tmp/initramfs/init(bearbeiten Sie es als root):

maybe_break mount
log_begin_msg "Mounting root file system"
. /scripts/${BOOT}
parse_numeric ${ROOT}
maybe_break mountroot
mountroot
log_end_msg

Sie müssen nicht verstehen, wie das funktioniert. Alles, was Sie verstehen müssen, ist, dass dadurch das normale Dateisystem, das Sie enthält, root.squashfsan einem Mountpunkt bereitgestellt wird, der anscheinend über die ${rootmnt}Shell-Variable angegeben wird.

Mit anderen Worten, was wir ${rootmnt}an dieser Stelle haben, ist unsere VFAT-Partition (oder was auch immer wir über den root=Befehlszeilenparameter angegeben haben). Dieses Skript erledigt jetzt andere Aufgaben, z. B. das Verschieben aller virtuellen Dateisysteme an den ${rootmnt}Einhängepunkt. Daher müssen wir sicherstellen, dass alle benutzerdefinierten Aufgaben nach dem obigen Code ausgeführt werden.

Alles was Sie tun müssen, ist einfach so etwas nach dem obigen Code in das initramfs einzufügen /init:

# create some temporary directories under the initramfs's /run
# they will be our mountpoints and such, which will get moved
# by the default script to the actual root filesystem...
mkdir -m 755 /run/rootfs
mount -t tmpfs -o size=90%,mode=755,suid,exec tmpfs /run/rootfs
mkdir -m 755 /run/rootfs/drive /run/rootfs/ro /run/rootfs/rw /run/rootfs/.workdir

# move the original root that was mounted, temporarily
mount -n -o move "${rootmnt}" /run/rootfs/drive

# mount the squashfs and then the overlay to our designated locations
mount -t squashfs -o defaults,ro /run/rootfs/drive/root.squashfs /run/rootfs/ro
mount -t overlay -o lowerdir=/run/rootfs/ro,upperdir=/run/rootfs/rw,workdir=/run/rootfs/.workdir root "${rootmnt}"

# at this point we have our overlay root at ${rootmnt}!
# however, move the drive's filesystem mount to the new root
# this allows it to be accessed afterwards from /media/drive
# NOTE: this assumes you have the /media/drive dir in the root squashfs
mount -n -o move /run/rootfs/drive "${rootmnt}/media/drive"
rm -d /run/rootfs/drive

Das ist es. Das Skript wird wie gewohnt fortgesetzt, wobei das Root-Dateisystem das Overlay ist und alle seine Teile anschließend leicht zugänglich sind. Beachten Sie , dass keine Fehlerprüfung durchgeführt wird. Es liegt in Ihrem eigenen Ermessen, die obigen Befehle hinzuzufügen oder sicherzustellen, dass das overlayModul geladen ist.

Packen Sie jetzt einfach die initramfs:

sudo sh -c 'cd /tmp/initramfs && find . -print0 | cpio --null -ov --format=newc' | gzip -9 > /tmp/initrd.img

Und kopieren Sie /tmp/initrd.img auf Ihre SD-Karte oder wo auch immer. Vergessen Sie nicht, sich root.squashfsim Stammverzeichnis der VFAT-Partition zu befinden, obwohl dies offensichtlich leicht anpassbar ist und Sie dies nicht auf diese Weise tun müssen. Dies ist nur der "einfachste" Weg mit Syslinux (und sogar UEFI-Boot), keineswegs der beste.

Tut mir leid, ich weiß, dass Sie nach einem eingebetteten Gerät gefragt haben, aber ich weiß nicht, wie der Startvorgang dort funktioniert. Ich verwende nur ein Beispiel für x86, aber dieser Teil ist weniger wichtig (nur der syslinux.cfgTeil).

Bitte beachten Sie, dass dies den beschreibbaren Teil des machen overlayfswie tmpfs, was nicht das, was Sie wollten. Es kann jedoch leicht geändert werden , wenn Sie oben schauen, mounten Sie einfach etwas anderes für /run/rootfsanstelle von tmpfs, wohin auch immer Sie die Schreibvorgänge möchten.

kktsuri
quelle