Dem Admin ist die Uptime genauso wichtig, wie Sicherheitslecks zeitnah stopfen zu können. Beides auf einmal geht nicht, da ein Kernelpatch einen Reboot erfordert – bis jetzt.
Einen neuen Kernel zu installieren ist unter Admins zwar unbeliebt, stellt sie aber vor keine große Herausforderung. Die meisten Distributionen liefern mit Paketmanagement und Installationstools einfach zu verstehende Hilfsmittel. Ist der neue Kern geladen, installiert und im Bootloader registriert, vergehen nur wenige Minuten für einen Reboot [1]. Diese Downtime dauert für einige Anwendungen jedoch schon zu lange. Wer ein System betreut, auf dem sehr langwierige Berechnungen laufen, etwa bei einer Klimasimulation, oder das sehr viele Netzwerkverbindungen verwaltet, etwa einen Telefonserver oder Onlineshop, möchte am liebsten überhaupt keinen Reboot durchführen.
Kleine Fehler
Auf der anderen Seite sind Admins für die Sicherheit ihrer Systeme verantwortlich. Untersuchungen der letzten drei Jahre haben ergeben, dass Entwickler rund alle drei Wochen einen Fehler im Linux-Kernel entdecken, der etwa unerwünschte Informationen preisgibt oder Rechte von Benutzern fälschlicherweise erweitert. Durch das offene Entwicklungsmodell sind aber meist schnell Patches gefunden, die das Problem beheben.
Jeffrey Brian Arnold vom Massachusetts Institute of Technology hat in seiner Untersuchung [2] festgestellt, dass diese Softwareflicken in den meisten Fällen sehr einfach waren. 80 Prozent bestanden aus weniger als 15 Zeilen Code, mehr als die Hälfte waren kaum mehr als Einzeiler. Häufig entstehen die Fehler durch “Off by one Errors”, bei denen sich ein Entwickler etwa bei einer Array-Grenze verzählt hat. Entsprechend einfach lassen sich dann die Fehler beheben. Ein Beispiel für ein solches Patch für den Systemaufruf »prctl()«, der die unter CVE-2006-2451 registrierte Schwachstelle behebt, zeigt Listing 1. Das Problem, für das auch Exploits existieren, ist in einer Zeile Code behoben.
|
Listing 1: Patch für |
|---|
01 diff --git a/kernel/sys.c b/kernel/sys.c
02
03 --- a/kernel/sys.c
04 +++ b/kernel/sys.c
05 @@ -1991,7 +1991,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
06 case PR_SET_DUMPABLE:
07 - if (arg2 < 0 || arg2 > 2) {
08 + if (arg2 < 0 || arg2 > 1) {
09 error = -EINVAL;
10 break;
11 }
|
Arnold kam die Idee, den laufenden Kernel direkt und ohne Neustart zu modifizieren, und hat dazu das Paket Ksplice entwickelt [3]. Das enthaltene Programm benötigt nur die Quellen des aktuell laufenden Kernels, seine Konfiguration und die Symboltabelle. Das Beste: Ksplice erfordert keine Vorbereitung des laufenden Systems, das Programm kann jeden Kern ab Version 2.6.8 modifizieren.
Den dazu benötigten Quelltext des Kernels bieten die Distributionshersteller an oder er liegt noch seit dem eigenen Übersetzen in »/usr/src«. Die beiden Dateien »config« und »System.map« legen die Distributionen üblicherweise in »/boot« ab. Ksplice benötigt zusätzlich nur noch ein Patch-File oder eine oder mehrere modifizierte Dateien. Das Programm übersetzt nun zwei neue Kernel: Mit »pre« bezeichnet es eine Version des laufenden Systems, mit »post« den Kernel nach den Updates.
Unterschiede finden
Sind beide Kernel gebaut, sucht Ksplice nach Unterschieden im Objektcode (siehe Abbildung 1). Dass es nicht den Quelltext vergleicht, hat mehrere Gründe: Das Programm vermeidet damit einige Probleme, die sich ergeben, wenn ein anderer Compiler den laufenden Kernel übersetzt hätte. Befindet sich das Patch etwa in einer Inline-Funktion, kann ein Compiler von Fall zu Fall entscheiden, ob er den Inline-Hinweis anwendet oder nicht.

Abbildung 1: Um Änderungen am laufenden Kernel vorzubereiten, übersetzt Ksplice zwei Kerneltrees (Stufe 1): Zum einen die Quellen des aktiven Linux, zum anderen die gepatchte Version. Unterschiede bestimmt es auf der Ebene des Object-Code (Stufe 2), optimiert sie (Stufe 3) und sammelt sie in einem neuen Modul (Stufe 4).
Würde das Patch-Programm direkt den Sourcecode analysieren, müsste es alle Entscheidungen des Compilers nachstellen – zu aufwändig für diesen Zweck. So sucht es mit Hilfe der GNU-BFD-Bibliothek [4] nach allen Funktionen im Objektcode, die sich im neuen Kern geändert haben. Den veränderten Code nimmt Ksplice in Module auf und bereitet so genannte Trampolin-Sprünge am Anfang der alten Funktionen vor, die fortan auf die neuen Versionen zeigen. Aktiviert der Admin schließlich die so vorbereitete Änderung, lädt Ksplice zwei Kernelmodule in das laufende System, die ihrerseits die Modifikationen nachziehen (siehe Abbildung 2).

Abbildung 2: Um die neuen Funktionen zu aktivieren, will Ksplice Trampolin-Sprünge an den Anfang der alten Funktionen schreiben. Dazu hält das Programm zunächst die Prozesse an und vergewissert sich, dass sich kein Thread im betreffenden Code befindet. Dann installiert es die Umleitungen.
Kritisch ist vor allem die Frage, wann Ksplice die Trampolin-Sprünge installieren darf. Befindet sich ein Kernelthread in den auszutauschenden Funktionen, sind Probleme zu erwarten. Das Programm stoppt daher mittels »stop_machine_run()« die Ausführung von Threads, weil die Funktion für jede CPU einen Prozess mit einer sehr hohen Priorität erzeugt. Nun prüft das Ksplice-Modul, ob sich Threads in den Änderungskandidaten befinden. Ist dies der Fall, wartet das Modul eine Weile und versucht sein Glück erneut. Bei einigen Funktionen, etwa dem Scheduler, schlägt das Verfahren fehl, da sich praktisch immer ein Prozess in ihnen befindet. In diesem Fall gibt Ksplice auf, andernfalls installiert es die Sprungadressen. Fortan führt der Linux-Kern die gepatchten Funktionen aus.
Innere Werte
Was einfach klingt, ist im Detail mit so mancher Tücke behaftet. Ksplice muss die richtigen Funktionen und Einsprungadressen auch in relozierbarem Code finden. So ist es in der Lage, zu erkennen, wenn sich relative Sprungsadressen zwar durch eine neue Länge von gepatchten Funktionen ändern, aber die Funktionen selbst nicht von einer Modifikation betroffen sind. In C implementierte Funktionen betritt der Kernel typischerweise nur an deren Anfang. Bei Assemblercode muss das Programm hingegen erst nach Einsprungadressen suchen.
Nutzt das Programm einen anderen Compiler, um den »pre«-Kernel zu erzeugen, könnten die Annahmen über das laufende System falsch sein. Ksplice behilft sich hier mit einer umfangreichen Logik, die die Symboltabellen analysiert, die viele Distributionen in »/boot/Symbol.map« ablegen. Zusätzlich übersetzt es die beiden erzeugten Kernel mit einer Reihe von Compiler-Optionen, die jeder Funktion ein eigenes ELF-Text-Segment zuweist, um veränderte relative Sprünge besser zu erkennen.
Einige Fälle kann Ksplice konzeptbedingt nicht berücksichtigen. Da es Code wie eine Blackbox behandelt, kann es Änderungen in Datenstrukturen nicht erkennen. Fügt ein Patch etwa ein neues Attribut in einer Datenstruktur ein oder ändert ihren Aufbau, kommt es unweigerlich zu Problemen, deren Effekte nicht absehbar sind. Funktionspointer sollten normalerweise die Trampolin-Sprünge auffangen, aber ob Ksplice auch komplexere Pointer-Arithmetik oder “kreative” Typecasts in jedem Fall behandeln kann, bleibt zweifelhaft.
Grenzen abschätzen
Der Autor unterstreicht in seiner Dokumentation dann auch, dass er das Werkzeug hauptsächlich für kleine Sicherheitspatches vorgesehen hat und dass es in der Verantwortung des Systemverwalters liegt, das angewendete Patch zu lesen, zu verstehen und zu bewerten. Insofern ist eine Menge Know-how der Kernelstrukturen nötig, um das Tool anzuwenden, ansonsten sind die Effekte womöglich verheerender als die Downtime eines Reboots.
Weil Ksplice keine semantischen Änderungen an einem laufenden Kernel vornehmen kann, platzen leider auch die Träume all jener, die von Uptimes in der Größenordnung von Jahren geträumt haben. Schließlich bestehen die meisten Änderungen von einer Kernelrelease zur nächsten aus solchen Änderungen und fügen ganz neue Funktionalität hinzu.
Im Einsatz
Die aktuelle Version 0.8.6 kommt als Tar-Archiv mit fertigen Binaries oder alternativ dem unter der GPLv2 stehenden Quellcode daher. Noch gibt es keine Distributionspakete. Wer das überschaubare Paket selbst aus dem Quellen übersetzen möchte, benötigt zusätzlich die BFD-Bibliothek, die bei von Debian oder Ubuntu abgeleiteten Distributionen etwa das Kommando
sudo aptitude install binutils-dev
installiert. Auf der Kernel-Mailingliste haben einige hochrangige Entwickler, darunter Andi Kleen, angeregt Ksplice als Upstream-Erweiterung in den offiziellen Kernel aufzunehmen. Kleen verspricht sich davon einen dauerhafteren Support des Projekts und langfristig eine Entwicklung, die zu einem inkrementellen Compiler führt [5]. Auf diese Weise müssten die Entwickler nicht jedes Mal einen kompletten Rebuild des Kernels ausführen, wenn sie ein Patch testen und verbessern. Bis zum Redaktionsschluss war die Aufnahme allerdings noch nicht geschehen.
Das Programm selbst besteht aus vier Perl-Skripten, die eine Reihe von in C implementierten Hilfsprogrammen zur Analyse des Objektcode aufrufen. Das Kommando »ksplice-create« benötigt nur den Pfad zu einem Verzeichnis eines laufenden Kernels und Angaben über das Patch. Praktischerweise darf der Administrator alternativ eine Änderung im »diff«-Format mit der Option »–patch« oder eine Dateierweiterung mit der Option »–diffext« nennen, in denen die Änderung bereits vollzogen ist. Zusätzlich benötigt das Programm im Kerneltree ein Unterverzeichnis »ksplice«, in das der Administrator sowohl die Kernelkonfiguration als auch die Symboltabelle ablegt (siehe Abbildung 3).

Abbildung 3: Um Ksplice vorzubereiten, gibt der Administrator dem Programm »ksplice-create« den Ort der Kernelquellen und die Art der Patches bekannt. Daraufhin baut es den alten und neuen Kernel und packt die Änderungen in ein Update-Modul. Ein wenig Zeit muss der Administrator aber dafür schon mitbringen.
Dieser erste Schritt dauert je nach verwendetem System eine gute Weile, da Ksplice zwei komplette Kernel übersetzt, die in »ksplice/pre« und »ksplice/post« liegen. Anschließend sucht das Programm nach den Unterschieden, optimiert sie und fasst das Ergebnis in zwei Kernelmodulen zusammen.
Der Hot-Fix lässt sich nun mit »ksplice-apply« einspielen. Zunächst lädt das Programm ein Modul, das sich um die Verwaltung der Trampoline kümmert und dazu einen geeigneten Zeitpunkt abwartet. Ist dieser gefunden, lädt es die Änderungen in den Kern, führt sie durch und entfernt sich dann selbst wieder, um Speicher zu sparen.
Flickenverwaltung
Ksplice ist auch in der Lage, einen bereits gepatchten Kernel erneut zu verändern. Dazu müssen allerdings die Flicken der ersten Stufe im »pre«-Tree des Quelltextes enthalten sein. Die Trampoline berücksichtigen »ksplice-create« und »ksplice-apply« und passen sie entsprechend an. Mit dem gleichen Mechanismus lassen sich die Änderungen mittels »ksplice-undo« sogar wieder zurücknehmen, da sich das System die ursprünglichen Einsprungadressen merkt. Die von Ksplice durchgeführten Änderungen zeigt schließlich »ksplice-view« an.
Ksplice-Autor Arnold zeigt auf seiner Website noch ein weiteres Einsatzszenario für sein Werkzeug: In beschränktem Maße lässt es sich zum Debugging des laufenden Kernels verwenden. Wer an einzelnen Stellen etwa nur einige »printk()«-Aufrufe einfügen möchte, um bestimmte, sonst schwer zugängliche Datenstrukturen anzusehen, findet mit Ksplice einen einfachen Weg, diese in das laufende System einzufügen. Komplexere Änderungen sind damit allerdings nicht ohne Weiteres möglich, hier bieten sich wohl doch eher dynamisch ladbare Module, Kprobes oder das darauf aufsetzende Systemtap an.
Patenter Ansatz?
Kurz nach Erscheinen der Ankündigung wiesen Entwickler auf der Mailingliste darauf hin, dass Microsoft im Dezember 2002 unter dem Titel “Patching of In-Use Functions on a Running Computer System” (10/307,902) einen Antrag auf ein Softwarepatent beim United States Patent Office (USPO) gestellt hat [6]. Das USPO lehnte den Antrag zwar ab, aber Microsoft hat Einspruch eingelegt und eine ganze Reihe weiterer Anträge gestellt, etwa zu Efficient Patching (USPO-Referenz 20050257208).
In verschiedenen Foren meldete sich prompt ein halbes Dutzend Entwickler, die feststellten, dass sie auf vielen verschiedenen Plattformen von einer PDP-11 bis hin zu einem modernen PC diese Technik schon lange vor dem Softwarepatentantrag eingesetzt haben.
Cleverer Helfer für bestimmte Situationen
Ksplice hat eine ganze Reihe schlauer Mechanismen eingebaut, die Hot-Updates eines Kernels auf Binärebene überhaupt erst möglich machen. Die Methoden zum Codeverschieben und für die Analyse von Einsprungadressen dürfen allerdings nicht darüber hinwegtäuschen, dass in jedem Fall der Systemverwalter manuell prüfen muss, ob sich das Werkzeug überhaupt anwenden lässt. Eine Garantie stellt ihm nämlich niemand darüber aus. So bleibt Ksplice ein nützlicher Helfer für einfache Fälle, aber ein doppeltes Auffangnetz in Form einer HA-Failover-Lösung sei dennoch allen Administratoren angeraten, für die eine sehr hohe Verfügbarkeit ihres Systems wichtig ist.
|
Infos |
|---|
|
[1] Eva-Katharina Kunst, Jürgen Quade, “Kernel 2.6 installieren”: Linux-Magazin 02/04, S. 28 [2] Jeffrey Brian Arnold, “Ksplice: An automatic system for rebootless Linux kernel security updates”: Massachusetts Institute of Technology, [http://web.mit.edu/ksplice/doc/ksplice.pdf] [3] Ksplice, Download und Installation:[http://web.mit.edu/ksplice/] [4] GNU Binutils und BFD-Bibliothek:[http://sourceware.org/binutils/] [5] Ankündigung und Diskussion auf der Linux-Kernel-Mailingliste: [http://thread.gmane.org/gmane.linux.kernel/669951] [6] Recherche beim United States Patent Office: [http://portal.uspto.gov/external/portal/pair] |






