Das „Jahr des Linux-Desktops“ mag zwar jedes Jahr verschoben werden, aber Linux dominiert mittlerweile so gut wie jedes andere Marktsegment – von Servern, Industriemaschinen und Mobiltelefonen (via Android) bis hin zu einer Vielzahl von Embedded-Geräten.
In der modernen, vernetzten Welt ist es wichtiger denn je, sicherzustellen, dass alle Geräte mit den neuesten Sicherheits- und Funktionsupdates auf dem aktuellen Stand gehalten werden. In diesem Artikel tauchen wir in die Möglichkeiten ein, Systemupdates auf verschiedenen Linux-Varianten zu verwalten.
Doch zunächst wollen wir sehen, wie sich dies im Vergleich zu kleineren Embedded-Geräten unterscheidet.
Was ist „Firmware“?
Grob gesagt gibt es zwei Haupttypen von Architekturen, die für Embedded-Geräte (IoT) verwendet werden können:
- Eine Mikrocontroller-Einheit (MCU), die typischerweise einen kleinen Prozessor und höchstens ein paar Megabyte Flash-Speicher und RAM in einem einzigen Paket integriert. Eine MCU führt normalerweise entweder „Bare-Metal“-Anwendungen oder ein Echtzeitbetriebssystem (RTOS) wie FreeRTOS oder Zephyr aus. Software auf solchen Geräten ist weitgehend monolithisch, wobei alles vom Betriebssystem über Treiber bis hin zu Anwendungen in einer einzigen Binärdatei kompiliert wird, die in einem einzigen Speicheradressraum läuft. Es gibt typischerweise kein Dateisystem, zumindest nicht für die Firmware, obwohl eines für Einstellungen oder die Interaktion mit externen Medien verwendet werden kann.
- Eine zentrale Prozessoreinheit (CPU), die mit externem RAM und Massenspeicher verbunden ist. Auf Embedded-Plattformen sind diese oft mit zusätzlichen Peripheriegeräten integriert und bilden ein System-on-a-Chip (SoC). CPUs führen in der Regel vollwertige Betriebssysteme aus, typischerweise Linux, die Prozesse, getrennte Adressräume, Speicherschutz und ein Dateisystem unterstützen.
Natürlich kann man auch ein RTOS auf einem großen SoC oder sogar einem Desktop-Computer ausführen, und es gibt Linux-Varianten, die auf einige MCUs passen.
Für diejenigen aus der MCU/RTOS-Welt ist die „Firmware“ jene einzelne ausführbare Datei, die man beim Linken von RTOS, Treibern, Bibliotheken und Anwendungscode erstellt. Sie residiert normalerweise in einem bestimmten Bereich von Flash-Speicheradressen, wobei der Rest oft für den Bootloader, Swap-Speicher für Firmware-Updates und nicht-flüchtigen Einstellungsspeicher reserviert ist. Es gibt einige mögliche Ansätze für Firmware-Updates, aber die allgemeine Idee ist, eine Binärdatei durch eine andere Version zu ersetzen. Diese Binärdateien sind einfach Daten-Blobs, und da nur eine einzige Binärdatei erstellt wird, ist die Versionierung recht einfach – wenn Sie Firmware bauen, geben Sie ihr eine Versionsnummer und das war's. Sie können den RTOS-Kernel nicht aktualisieren, ohne die gesamte Firmware neu zu erstellen, sodass das gesamte Abhängigkeitsmanagement und die Versionskontrolle zur Kompilierzeit auf den Entwicklermaschinen stattfinden muss.
Nutzer von Desktop-Computern wissen, dass größere Betriebssysteme völlig anders sind. Tatsächlich wird das Betriebssystem bei vollwertigen Computern selten als „Firmware“ bezeichnet. Der Begriff bleibt meist für BIOS- oder UEFI-Software reserviert, die auf Ihrem Motherboard lebt und für die frühe Initialisierung der Hardware verantwortlich ist. Aber als Betriebsumgebung an sich ist sie nicht sehr nützlich.
Schauen wir uns also an, wie sich das auf verschiedene Arten von Linux-Systemen abbilden lässt. Um eine Basislinie zu erhalten, beginnen wir mit den traditionellen Desktop- und Server-Distributionen.
Verwalten Sie Firmware-Updates auf Ihren Geräten effizient mit AVSystem.
Arbeiten mit den „Großen“
Eine typische Desktop-Linux-Distribution – denken Sie an Ubuntu, Fedora, Arch oder sogar Raspberry Pi OS – ist im Wesentlichen eine Sammlung von Paketen. Vielleicht kennen Sie *.deb-Dateien und das apt-Tool unter Ubuntu oder Debian, oder *.rpm und dnf unter Fedora. apt und dnf sind Beispiele für Paketmanager, die Pakete installieren, deinstallieren und aktualisieren und gleichzeitig sicherstellen, dass sie gut zusammenarbeiten – zum Beispiel durch das Erzwingen von Abhängigkeiten.
Pakete existieren für gängige Software wie den Firefox-Browser oder LibreOffice sowie für Kernsystemkomponenten wie den Linux-Kernel, die C-Bibliothek oder den GRUB-Bootloader. Diese Kernkomponentenpakete enthalten oft zusätzliche Skripte, die für die Aktualisierung der Boot-Partition oder die Neukonfiguration des Bootloaders verantwortlich sind, um standardmäßig eine andere Kernel-Version zu verwenden. Der Hauptpunkt bleibt jedoch, dass das installierte System eine Sammlung von Paketen ist, die jeweils separat versioniert sind. Viele Pakete deklarieren Abhängigkeiten voneinander, z. B. benötigt ein Webbrowser möglicherweise die C-Bibliothek in einer Version von mindestens 2.17, aber älter als 3.0. Die Aufgabe eines Paketmanagers ist es, sicherzustellen, dass diese nicht beschädigt werden.
Sicherheits- und Funktionsupdates werden geliefert, indem neuere Paketversionen in ein zentrales Repository gepusht werden. Distributions-Maintainer stellen sicher, dass alle Pakete, die sich derzeit im Repository befinden, miteinander funktionieren, sodass Benutzer keine Abhängigkeitsprobleme haben sollten. Einige Distributionen, wie Arch, gelten als „Rolling Release“ – Pakete werden veröffentlicht, sobald die Software Upstream aktualisiert wird, sodass sowohl kleine Sicherheitsupdates als auch große Funktionsupgrades auf die gleiche Weise geliefert werden.
Bei traditionelleren Distributionen wie Ubuntu gibt es jedoch separate Repositories für jedes OS-Release – die meisten Mainstream-Distributionen werden zweimal jährlich veröffentlicht. Kernpakete werden innerhalb eines OS-Releases normalerweise nicht auf neue Hauptversionen aktualisiert. Ein In-Place-Upgrade auf ein neueres Release ist jedoch relativ ähnlich – das Betriebssystem wird so konfiguriert, dass es die Repositories eines neueren Releases verwendet, und es wird ein ansonsten weitgehend normales System-Upgrade durchgeführt – möglicherweise mit zusätzlichem Scripting, um größere architektonische Änderungen zu bewältigen (wie z. B. der Wechsel des Init-Systems von sysvinit zu Upstart und dann zu systemd).
Dieser Ansatz ist sehr flexibel, da er es Distributions-Maintainern ermöglicht, Updates für jede Systemkomponente separat zu pushen, was die Update-Downloads klein hält. Es bedeutet jedoch auch, dass jede einzelne Installation einzigartig ist und Update-Probleme möglicherweise nicht leicht reproduzierbar sind. Zudem wird im Allgemeinen erwartet, dass der Benutzer während des Update-Prozesses anwesend ist, um eventuell auftretende Probleme zu beheben. Wenn beispielsweise Konfigurationsdateien auf eine Weise geändert wurden, die der Paketmanager nicht handhaben kann, ist dieser Ansatz für automatisierte Remote-Updates ungeeignet. Nicht nur das, es gibt auch sehr wenig Fehlerresistenz – ein erfolgloses Update hinterlässt das System wahrscheinlich in einem inkonsistenten und möglicherweise nicht mehr bootfähigen Zustand. Traditionelle Distributionen erzwingen normalerweise auch keine Systemintegrität – Sie können Dinge installieren, die keine Pakete sind (z. B. Software selbst kompilieren), für die Abhängigkeiten in keiner Weise verfolgt werden – nachfolgende System-Upgrades können diese Software leicht beschädigen oder sogar Konflikte verursachen.
Moderne Distributionen unterstützen auch containerisierte Anwendungspakete wie Snap oder Flatpak, die vermeiden, die nativen Kernpakete der Distribution so weit wie möglich zu verwenden. Stattdessen führen sie Anwendungen in ihren eigenen Sandboxes mit dedizierten Kernkomponenten aus – von denen verschiedene Versionen nebeneinander laufen können. Ich werde diese Themen jedoch vorerst beiseite lassen.
Die unveränderliche Lösung
Commercial operating systems have long alleviated these problems by introducing mechanisms that prevent key system files from being modified. You might have heard about the System File Checker on Windows or System Integrity Protection on macOS. If you try to mess with files in the C:\Windows\System32 or /System directories, the OS will prevent you from causing damage, even if you’re running with administrative privileges.
Kommerzielle Betriebssysteme haben diese Probleme längst gelindert, indem sie Mechanismen eingeführt haben, die verhindern, dass wichtige Systemdateien geändert werden. Vielleicht haben Sie vom System File Checker unter Windows oder der System Integrity Protection unter macOS gehört. Wenn Sie versuchen, Dateien in den Verzeichnissen C:\Windows\System32 oder /System zu manipulieren, wird das Betriebssystem Sie daran hindern, Schaden anzurichten, selbst wenn Sie mit administrativen Rechten arbeiten.
Nicht nur das – unter macOS Catalina und neuer liegt die Basis-Systeminstallation auf einem separaten, schreibgeschützten Volume, und alle vom Benutzer vorgenommenen Änderungen werden darübergelegt, aber logisch getrennt. Windows hat eine solche Funktion auf Dateisystemebene nicht – aber es verfolgt, wie ein „sauberes“ System aussehen sollte, sodass Sie die Funktion „Diesen PC zurücksetzen“ verwenden können, um es funktional wiederherzustellen, auch ohne Installationsmedien oder Downloads.
Seit Mitte der 2010er Jahre haben verschiedene Linux-Distributionen versucht, diese Prinzipien – oft als „unveränderliche“ (immutable) oder „atomare“ Distributionen bezeichnet – in der Welt der freien Software zu replizieren. Die grundlegende Idee ist, den größten Teil des Dateisystems schreibgeschützt zu haben und den Benutzer zu ermutigen, Software containerisiert zu installieren. Die Details hängen jedoch stark von der spezifischen Distribution ab. Hier sind ein paar Beispiele:
-
Fedora Silverblue startete 2014 als Project Atomic und ist seit Ende 2018 eine offizielle Variante von Fedora. Zusammen mit seinen anderen unveränderlichen Geschwistern wie Fedora IoT und CoreOS ist es wohl die „ursprüngliche“ unveränderliche Distribution für den Desktop. Wie auch immer wir es qualifizieren mögen, es stützt sich stark auf OSTree, eine Software, die das gesamte Root-Dateisystem ähnlich wie ein Git-Repository behandelt. Updates für die Basis-Distribution werden veröffentlicht, indem die Entwickler einen neuen „Commit“ in das OS-Repository pushen. Es bietet eine Möglichkeit, den „Commit“ beim Booten auszuwählen, was bedeutet, dass Sie einfach die zuvor funktionierende Version beim Booten auswählen können, wenn etwas schiefgeht. Sie werden ermutigt, Drittanbietersoftware über Container wie Flatpak zu installieren, aber für Low-Level-Dinge wie Treiber kann das
rpm-ostree-Tool verwendet werden, um beliebige Pakete als „Commits“ über das Upstream-Basissystem zu schichten (Layering). Diese Änderungen werden beim Aktualisieren des Systems erneut angewendet – und wenn etwas schiefgeht, können Sie immer beim Booten in den ursprünglichen Zustand wechseln. -
Ubuntu Core, erstmals als Variante von Ubuntu 15.04 „Vivid Vervet“ veröffentlicht, ist die Referenzdistribution für das Snap-Paketierungssystem. Snap-Container sind im Wesentlichen schreibgeschützte SquashFS-Images, die bei Bedarf gemountet werden – und Ubuntu Core bootet durch eine ausgefeilte Bootloader-Konfiguration direkt in den „Core“-Snap und erlaubt nur das Ausführen anderer Snap-Pakete. Wenn Sie etwas anderes benötigen, müssen Sie es durch etwas wie Docker oder sogar nur chroot containerisieren. Snap ermöglicht die Installation mehrerer Versionen desselben Pakets nebeneinander; wenn es also Abhängigkeiten zwischen Paketen gibt, sieht jedes seine eigene virtualisierte Ansicht des Dateisystems, wobei nur die richtigen Abhängigkeiten vorhanden sind. Updates werden bereitgestellt, indem neuere Versionen der Pakete in den Snap Store aufgenommen werden, und Sie können in eine ältere Version des „Core“-Snaps booten, wenn etwas schiefgeht. Ubuntu Core ist eine auf IoT fokussierte Distribution, aber eine Desktop-Variante, die auf denselben Prinzipien basiert, ist für 2024 geplant.
-
Vanilla OS ist eine recht neue Distribution basierend auf Ubuntu 22.10, die sich tatsächlich mehr auf Atomizität und Transaktionalität als auf Unveränderlichkeit konzentriert. Bei der Installation erstellt es zwei Kopien des Root-Dateisystems – „A“ und „B“, die schreibgeschützt gemountet sind. Updates und andere Wartungsaufgaben laufen ähnlich wie auf einem traditionellen Ubuntu-System ab, werden aber nicht direkt in das laufende Dateisystem geschrieben. Stattdessen erstellt eine Software namens ABRoot eine Aufzeichnung von Änderungen gegenüber dem aktuellen Zustand, und die „gegenüberliegende“ (z. B. B, wenn A gerade läuft) Partition wird aktualisiert, um den neuen Zustand widerzuspiegeln, der nach einem Neustart verwendet wird. Auf diese Weise ist der letzte bekannte funktionierende Zustand immer als Fallback verfügbar. Beliebige Transaktionen werden auf diese Weise unterstützt, sodass Software über traditionelle Pakete installiert werden kann, auch wenn containerisierte Technologien bevorzugt werden.
-
SteamOS auf dem Steam Deck treibt das „A/B“-Konzept noch weiter – die Partitionen werden auf Blockebene mit den OS-Releases synchron gehalten, d. h. der Zustand auf der Festplatte ist Bit für Bit identisch mit einer veröffentlichten Version. Beim Update wird die „gegenüberliegende“ Partition mithilfe von RAUC und desync mit einem Remote-Image synchronisiert – selbst wenn der Benutzer die Partition in irgendeiner Weise geändert hat, stellt dieser Synchronisierungsprozess den ursprünglichen Zustand wieder her. Drittanbietersoftware wird hauptsächlich über Containerisierung und benutzerlokale Installation unterstützt. Der Benutzer kann den Schreib-Lese-Zugriff auf das Root-Dateisystem wieder aktivieren, aber solche Änderungen werden beim nächsten Systemupdate verworfen. Overlays wie
systemd-sysextkönnen verwendet werden, um Änderungen dauerhaft zu machen, obwohl Abhängigkeiten jederzeit brechen können. -
Schließlich bietet Android seit Version 11 einen „Virtual A/B“-Mechanismus, der das Konzept der A/B-Images verbessert, indem er den Speicherbedarf minimiert. Auf logischer Ebene funktioniert das Verfahren wie oben für das Steam Deck beschrieben, aber die „A“- und „B“-Partitionen sind virtuell – ein spezieller Treiber ordnet physikalische Blöcke des Flash-Speichers so neu zu, dass unveränderte Blöcke nicht dupliziert werden und aktualisierte Blöcke komprimiert werden können.
Alle diese Ansätze gehen verschiedene Kompromisse zwischen Flexibilität, Zuverlässigkeit und Speichereffizienz ein. Jeder ist jedoch so konzipiert, dass er direkt von den Endbenutzern aufgerufen und gewartet werden kann. In der Welt der Embedded-Systeme haben Zuverlässigkeit und Vorhersehbarkeit oft Vorrang, was zu automatisierten Remote-Updates führt, die ohne direkte Interaktion des Benutzers mit dem System ausgeführt werden. Andererseits ist Flexibilität normalerweise nicht so wichtig, da Software im Allgemeinen nicht als Teil der normalen Nutzung installiert oder deinstalliert wird.
Updates in Embedded Linux verstehen
Es gibt kein einzelnes Handbuch für jede Anwendung. Einige Embedded-Systeme entscheiden sich möglicherweise für traditionelle paketbasierte Distributionen, wenn eine bestimmte Anwendung eine solche Flexibilität erfordert. Andere entscheiden sich vielleicht für Unveränderlichkeit auf Dateisystemebene unter Verwendung von Lösungen wie OSTree.
Das gängigste Update-Paradigma scheinen jedoch Updates auf Blockebene von unveränderlichen Partitionen zu sein. Dies gibt es in zwei Hauptvarianten:
- Symmetrische (A/B) Images: Wie oben für Vanilla OS und SteamOS beschrieben, werden zwei funktional gleichwertige Kopien des Betriebssystems auf dem Speichermedium installiert, und jedes Update flasht neu auf dasjenige, das gerade nicht läuft. Die Rollen werden nach einem erfolgreichen Upgrade getauscht, aber die vorherige Version bleibt als „Last Known Good“-Status erhalten, um bei einem Fehler ein Rollback durchzuführen.
-images_(1).jpg)
- Asymmetrische (Haupt- + Wiederherstellungs-) Images: Das System verfügt im Wesentlichen über ein Dual-Boot zwischen einem „Haupt“-Betriebssystem, das alle normalen Funktionen des Geräts bereitstellt, und einer speziellen „Wiederherstellungs“-Partition (Recovery), die für Reparaturen und auch für Updates verwendet werden kann. Der Update-Prozess beinhaltet einen Neustart in das Recovery-Image, das die „Haupt“-Partition neu flasht – entweder durch eigenen Download oder unter Verwendung eines vor dem Neustart heruntergeladenen Images. Falls etwas schiefgeht, können Download und Flash-Vorgang wiederholt werden, wenn das Recovery-Image erneut gebootet wird.
-images.jpg)
Beachten Sie, dass das Partitionslayout komplizierter sein kann als nur zwei „A/B“- oder „Haupt+Recovery“-Partitionen. Tatsächliche Layouts enthalten in der Regel auch eine Partition für nicht-flüchtige Daten wie Konfigurationsdateien oder Benutzerspeicher sowie eine zusätzliche Partition für den Bootloader. Getrennt vom Hauptsystem-Image können sich auch der Linux-Kernel, Peripherie-Firmware und zusätzliche Anwendungen befinden. Im Falle des A/B-Paradigmas können diese entweder neben jedem der A/B-Root-Dateisysteme dupliziert oder von beiden gemeinsam genutzt werden.
Die Root-Dateisystempartition selbst kann auf einem laufenden System schreibgeschützt gemountet sein oder auch nicht. Manchmal ist es einfacher, sie mit Schreib-Lese-Zugriff zu mounten, damit Software, die z. B. Systemprotokolle und andere flüchtige Daten auf die Festplatte schreibt, unverändert laufen kann. In einem solchen Fall wird jedoch erwartet, dass alle solchen Daten nach einem Upgrade verloren gehen. Tatsächlich nicht-flüchtige Daten müssen also auf einer separaten Lese-Schreib-Partition liegen, und die Software muss angewiesen werden, diese zu verwenden – entweder über Konfigurationen zur Kompilierzeit, Symlinks auf der Root-Partition oder als Overlay gemountet.
Wie bereits erwähnt, ist das A/B-Paradigma auch die Grundlage für System-Upgrades unter anderem bei ChromeOS, Android und SteamOS. Andererseits sollte das „Haupt+Recovery“-Paradigma Laptop-Benutzern bekannt vorkommen – eine Wiederherstellungspartition, die eine Neuinstallation des Betriebssystems aus dem Internet ermöglicht, ist seit Mac OS X Lion (2011) Standard auf Apple-Computern. Die Windows-Wiederherstellungsumgebung, wenn auch etwas eingeschränkter, ist seit Windows Vista (2006) verfügbar, während Windows-Laptop-Hersteller dafür bekannt waren, Jahre zuvor benutzerdefinierte Wiederherstellungspartitionen einzuführen.
Das A/B-Paradigma sollte sich auch für diejenigen vertraut anfühlen, die Erfahrung mit Lösungen auf Basis von MCUs und RTOSes haben. Es gibt jedoch einige Unterschiede im Upgrade-Ablauf (Flow). Bei RTOS-basierten Geräten ist der Großteil der Upgrade-Logik im Bootloader wie MCUboot oder X-CUBE-SBSFU enthalten. Der typische Ablauf beinhaltet das Schreiben des rohen Update-Images auf die inaktive Partition, und der Bootloader erledigt den Rest nach einem Neustart, was das Tauschen der beiden Partitionen, das Überprüfen von Prüfsummen und kryptografischen Signaturen oder sogar das Entschlüsseln eines verschlüsselten Images umfassen kann. Bei Linux-basierten Geräten werden alle diese Aufgaben typischerweise von der Updater-Software vor dem Neustart ausgeführt.
Die einfachste Form einer solchen „Updater-Software“ führt einfach eine Bit-für-Bit dd-Kopie vom Update-Image auf die Systempartition durch und schaltet vielleicht ein Flag im Bootloader um, um von der zuvor inaktiven Partition zu booten. Es gibt jedoch eine Reihe zusätzlicher Funktionen, die für eine Produktionslösung wünschenswert sind, darunter:
-
Integritätsprüfungen, um sicherzustellen, dass das geflashte Image nicht beschädigt ist und bootfähig sein wird.
-
Kryptografische Signaturprüfungen, um sicherzustellen, dass das Image von einem vertrauenswürdigen Anbieter stammt und nicht manipuliert wurde.
-
Unterstützung für verschlüsselte Images, um Analyse oder Reverse Engineering zu erschweren.
-
Unterstützung für Delta-Images oder Chunked Downloads, damit nicht bei jedem Upgrade das gesamte Image von Grund auf neu heruntergeladen werden muss.
-
Scripting-Unterstützung, damit z. B. Konfigurationsdateien und andere nicht-flüchtige Speicher zwischen Upgrades aktualisiert oder migriert, der Bootloader neu konfiguriert werden kann und so weiter.
-
Integrierte OTA-Funktionalität, damit das Gerät prüfen kann, ob ein neues Update-Image verfügbar ist, und es automatisch anwenden kann.
Zusätzlich bietet der Linux-Kernel dort, wo Manipulationssicherheit wichtig ist, eine weitere Sicherheitsebene – das dm-verity-Modul. Dies ermöglicht die Erstellung eines Hash-Baums, der die Erkennung jeglicher Datenmodifikation auf dem geschützten Blockgerät ermöglicht.
dm-verity ist standardmäßig auf Android- und ChromeOS-Geräten aktiviert und kann auch auf jedem Embedded-Gerät verwendet werden. Wenn es mit anderen Härtungstechniken wie Secure Boot und Kernel-Modul-Signierung kombiniert wird, kann ein Gerät erstellt werden, das immer nur verifizierte und signierte Dateisystem-Images ausführt.
Um all diese Funktionen zu unterstützen, entstand eine spezialisierte Klasse von Software zur Verwaltung von Software-Updates auf Embedded-Linux-Systemen.
Verwalten Sie Firmware-Updates auf Ihren Geräten effizient mit AVSystem.
Software zum Aktualisieren von Embedded-Linux-Systemen
In diesem Abschnitt erfahren Sie mehr über einige der leicht verfügbaren Open-Source-Softwarelösungen zur Verwaltung von Updates auf Embedded-Linux-Systemen.
SWUpdate
Laut seiner Github-Seite ist SWUpdate „ein Linux-Update-Agent mit dem Ziel, eine effiziente und sichere Möglichkeit zu bieten, ein Embedded-Linux-System im Feld zu aktualisieren“. Das Projekt selbst steht unter der GPLv2-Lizenz, kann aber auch über eine Bibliothek gesteuert werden, die unter LGPLv2.1 veröffentlicht wird. Die erste Veröffentlichung stammt aus dem Juli 2014, und das Projekt wird seitdem aktiv weiterentwickelt, wobei typischerweise zweimal im Jahr eine neue stabile Version veröffentlicht wird.
Es ist für Updates auf Blockebene für unveränderliche Dateisysteme konzipiert. Sein explizites Designziel ist, dass „SWUpdate konfiguriert werden sollte, um in ein Projekt zu passen, nicht umgekehrt“, sodass es auf so gut wie jedem Linux-System in vielen Paradigmen laufen kann, einschließlich sowohl „A/B“ als auch „Haupt+Recovery“. Das SWUpdate-Projekt selbst erzwingt keine Designentscheidungen beim Firmware-Anbieter, sodass Sie beispielsweise immer noch entscheiden müssen, wie Sie mit nicht-flüchtigem Speicher umgehen.
Die meisten Integrationen basieren entweder auf Yocto oder seltener auf Buildroot. Das swupdate-Paket ist im Upstream-Buildroot-Repository verfügbar, aber die gesamte Konfiguration sowohl des Systems (Partitionierung usw.) als auch des Updaters muss manuell bereitgestellt werden. Ebenso ist die grundlegende Integration mit Yocto als meta-swupdate-Layer verfügbar; einfache Konfigurationen für Raspberry Pi und Beaglebone-Geräte sind als meta-swupdate-boards verfügbar, diese sind jedoch nur als Beispiele gedacht, nicht als produktionsbereite Konfigurationen.
SWUpdate ist bis zu einem gewissen Grad modular und enthält folgende Teile:
-
SWUpdate Core: Kann eine Update-Datei nehmen und anwenden; die Datei kann entweder lokal verfügbar sein oder, je nach Konfiguration zur Kompilierzeit, on-the-fly mit libcurl heruntergeladen werden; der Core-Updater basiert auf der Befehlszeile, kann aber auch als Bibliothek verwendet werden.
-
Web Server / Mongoose: Bedient eine einfache lokale Webseite, die verwendet werden kann, um eine Update-Datei hochzuladen, indem man einen Webbrowser auf die IP-Adresse des Embedded-Geräts richtet.
-
Suricatta: Fragt einen kompatiblen OTA-Update-Server nach neuen Update-Paketen ab und wendet diese automatisch an.
SWUpdate definiert ein einheitliches Update-Dateiformat, das typischerweise die Endung *.swu verwendet. Unter der Haube ist es ein cpio-Archiv, das eine beliebige Anzahl von Archiven sowie eine Konfigurationsdatei enthalten kann, die beschreibt, wie diese angewendet werden sollen. Abhängig von der Konfiguration von SWUpdate zur Kompilierzeit kann die Konfigurationsdatei beliebiges Scripting in Lua oder Unix-Shell sowie das Signieren und/oder Verschlüsseln der Pakete unterstützen, wobei in diesem Fall eine ordnungsgemäße Signatur oder Entschlüsselung für ein erfolgreiches Upgrade erforderlich ist. Dieses Dateiformat ist so konzipiert, dass es linear „gestreamt“ werden kann – das heißt, on-the-fly angewendet wird, während es heruntergeladen wird, ohne dass ein Zwischenspeicher erforderlich ist.
SWUpdate unterstützt auch „Delta“-Images in zwei Formen – die Images können rdiff-Images sein, die denselben Algorithmus wie rsync nutzen, um über einen bekannten vorherigen Zustand angewendet zu werden. Alternativ kann die *.swu-Datei nur die Metadaten enthalten, während die eigentlichen Daten über das Netzwerk unter Verwendung eines zchunk-Formats synchronisiert werden.
SWUpdate ist in Embedded-Linux-Ökosystemen weit verbreitet, insbesondere in solchen, die auf Yocto basieren.
RAUC
RAUC
RAUC (Robust Auto-Update Controller) ist eine weitere Lösung, die laut den Worten ihrer Maintainer „den Update-Prozess auf Embedded-Linux-Systemen steuert“. Es ist ein neueres Projekt mit der ersten Veröffentlichung im Februar 2017 und wird mehrmals im Jahr aktualisiert. Es ist unter LGPLv2.1 lizenziert.
RAUC wird von Pengutronix entwickelt und ist in deren eigenes Embedded-Linux-Build-System, PTXdist, integriert. Offizielle Integrationen sind auch für Yocto (meta-rauc), Buildroot, Debian, Ubuntu, Arch Linux und NixOS verfügbar. Die Yocto-Integration wird zusätzlich durch Beispielkonfigurationen für eine Reihe beliebter Entwicklungsplattformen unterstützt, die über das meta-rauc-community-Repository bereitgestellt werden.
Ähnlich wie SWUpdate unterstützt RAUC sowohl „A/B“- als auch „Haupt+Recovery“-Paradigmen und mehrere Partitionen. Sein Update-Dateiformat, *.raucb (RAUC Bundle), ist ein SquashFS-Image, das zusätzlich seine Signatur, den Verity-Hash-Baum und möglicherweise auch eine Verschlüsselung enthalten kann. Innerhalb dieses Bundles befindet sich eine Manifest-Datei, die andere Komponenten beschreibt, sowie eine beliebige Anzahl von Images in verschiedenen Formaten – entweder Bit-für-Bit-Dateisystem-Images oder Verzeichnisarchive.
Update-Bundles können lokale Dateien sein oder bei Bedarf von einem HTTP(S)-Server heruntergeladen werden. Im Gegensatz zu SWUpdate werden On-Demand-Downloads jedoch über einen integrierten Netzwerk-Blockgerätetreiber und HTTP-Range-Anfragen abgewickelt. RAUC verlässt sich auf die Fähigkeit, das SquashFS-Bundle zu mounten, daher ist lineares Streaming ohne lokales Caching des gesamten Bundles nicht möglich.
Delta-Upgrades können entweder über einen integrierten „Adaptive Updates“-Mechanismus oder über casync oder desync gehandhabt werden. In allen drei Fällen wird die Download-Optimierung lokal durchgeführt, und das Update-Bundle muss in seiner Gesamtheit auf dem Update-Server verfügbar sein.
RAUC kann entweder über die Befehlszeile oder via D-Bus gesteuert werden. Es kümmert sich nur um das Anwenden der Updates, daher gibt es keinen integrierten Webserver oder automatische Update-Prüfungen. Im Allgemeinen ist es weniger flexibel, aber auch leichtgewichtiger als SWUpdate.
RAUC wird verwendet, um das Steam Deck und die Informationsterminals der ICE-Züge der Deutschen Bahn zu aktualisieren.
Mender
Mender taucht oft im Zusammenhang mit OTA-Updates auf Embedded-Linux-Geräten auf. Entwickelt von Northern.tech, ist es sowohl ein Open-Source-Projekt als auch ein kommerzielles Produkt, das auf Einfachheit ausgelegt ist. Während SWUpdate oder RAUC umfangreiche Konfigurationsoptionen bieten, um in jedes mögliche Projekt zu passen, konzentriert sich Mender auf den typischen Anwendungsfall der Aktualisierung von Systemen auf Basis von Yocto oder Debian unter Verwendung von OTA-Firmware- und Softwaremanagement über Menders eigene Serversoftware.
Sowohl Mender-Client als auch -Server sind Open Source, lizenziert unter Apache License 2.0. Northern.tech bewirbt jedoch stark seine eigenen gehosteten Instanzen des Mender-Servers, die zusätzliche kommerzielle Funktionen bieten. Die Client-Software ist ebenfalls eng mit der Server-Technologie gekoppelt, obwohl das Client-Programm auch die Durchführung von Standalone-Updates von lokalen Dateien oder beliebigen URLs unterstützt.
Mender-Artefakte sind signiert, unterstützen aber keine Verschlüsselung. Sie können vollständige Partitions-Images (entwickelt für das A/B-Paradigma), Delta-Images oder „Update-Module“ enthalten, die beliebiges Scripting unterstützen und für Updates auf Anwendungsebene verwendet werden können. Vollständige Partitions-Updates werden über das Netzwerk gestreamt, sodass die gesamte Datei nicht im Zwischenspeicher gespeichert werden muss.
Mender mag dank seiner Einfachheit und niedrigen Einstiegshürde wie eine sehr überzeugende Option erscheinen. Die enge Kopplung zwischen Client- und Server-Seite, kombiniert mit der Tatsache, dass es nicht auf offenen Standards basiert, bedeutet jedoch, dass Vendor Lock-in ein Problem sein kann. Es ist auch viel weniger flexibel und konfigurierbar als SWUpdate oder RAUC.
Wie passt AVSystem in all das hinein?
Bei AVSystem glauben wir, dass OMA SpecWorks’ Lightweight M2M (LwM2M) die richtige Lösung ist, nicht nur für das Remote-Management und Monitoring von IoT-Geräten, sondern auch für das Management des OTA-Firmware-Update-Prozesses. Unsere Coiote IoT-Gerätemanagement-Plattform bietet eine umfassende Lösung zur Verwaltung von Firmware-Update-Kampagnen sowohl auf einzelnen Geräten als auch auf ganzen Flotten.
Unsere LwM2M-Client-Bibliothek Anjay ist auf Systemen, die auf MCUs und RTOSes basieren, am beliebtesten, aber sie ist hochgradig portabel und kann auch auf Embedded-Linux-Systemen arbeiten. Anjay implementiert einen Firmware-Update-Zustandsautomaten (State Machine), der mit dem offenen Standard OMA LwM2M-Protokoll konform ist und es dem Benutzer ermöglicht, die Callbacks zu jedem gewünschten Backend zu implementieren. Dies kann sehr wohl SWUpdate, RAUC, Menders Standalone-Updater oder jede andere Update-Lösung für Embedded Linux sein.
Wie Sie im Tutorial nachlesen können, übernimmt Anjay den Download selbst und übergibt das Firmware-Image über die genannten Callbacks als linearen Byte-Stream an den Anwendungscode. Aus diesem Grund funktioniert diese Implementierung am besten mit Update-Agent-Software, die das Anwenden linearer Streams on-the-fly ermöglicht, wie SWUpdate oder Mender.
Es gibt zusätzliche Möglichkeiten zur Verwaltung von Updates im LwM2M-Ökosystem. Das Multi-Component Firmware Update wurde kürzlich in Anjay und Coiote eingeführt, was für die Aktualisierung nicht-monolithischer Systeme nützlich sein kann, zum Beispiel wenn einige Anwendungen einen anderen Release-Zyklus haben als das Betriebssystem selbst. Andererseits könnte die LwM2M Software Management-Spezifikation gut für Systeme geeignet sein, die auf traditionelleren Paketen (*.deb, *.rpm, etc.) oder Containern (z. B. Docker) basieren.
Fazit
Die Open-Source-Natur von Linux bedeutet, dass es unendlich anpassbar ist und in fast jede mögliche Anwendung passen kann. Es bedeutet auch, dass es eine Vielzahl möglicher Strategien zur Aktualisierung des Systems gibt. Es ist wichtig, die Vor- und Nachteile verschiedener Lösungen zu verstehen und eine auszuwählen, die für Ihre spezifische Anwendung geeignet ist. Open-Source-Firmware-Management-Software und leicht verfügbare OTA-Update-Server-Lösungen können helfen, diese Lösung zum Leben zu erwecken, während man den Best Practices des Embedded-Linux-Ökosystems treu bleibt.