|
Hat man eine Linux-Distribution (SuSE Linux, RedHat Linux oder
andere) installiert, so hat man sehr viele Komponenten
installiert. Neben dem Kernel (also Linux selbst) sind unzählige
Programme und natürlich Bibliotheken installiert worden. Die
Bibliotheksdateien befinden sich in den Verzeichnissen /lib und
/usr/lib. Etliche der installierten Programme verwenden auch
statisch gebundene Bibliotheken, aber da man davon im Betrieb
nichts merkt, wird das hier nicht näher betrachtet.
Die dynamischen, gemeinsam benutzbaren Bibliotheken sind für alle
Programme des Linuxsystems verwendbar. Neben der einfachen
Benutzung bietet ein Linuxsystem jedoch weitere Vorteile, die
anspruchsvolleren Anforderungen genügen.
Es ist möglich, zu einem Zeitpunkt verschiedene Versionen einer
Bibliothek installiert zu haben. Man kann in diesem Fall
beeinflussen, welche Bibliotheken ein Programm verwendet. So kann
man auch ältere Programme weiterverwenden, die eine alte,
inkompatible Version einer Bibliothek benötigen.
Man kann auch veranlassen, dass bestimmte Bibliotheken, die ein
Programm verwendet, gegen andere ersetzt werden, um damit
beispielsweise gezielt einzelne Funktionen zu ersetzen.
|
Soll ein Programm, welches Bibliotheken verwendet, gestartet
werden, so müssen diese natürlich mitgeladen werden. Dazu wird
zunächst gar nicht das eigentliche Programm gestartet, sondern
der sogenannte Programmlader (engl.: program loader). Dieser wird
auch "dynamic linker" genannt, da er die Bibliotheken zum
Programm bindet. Auf Linuxsystemen heißt dieser
/lib/ld-linux.so.2 (die .2 ist wieder eine Versionsnummer; das
"-linux" zeigt, dass er Linux spezifisch ist. Oft wird er jedoch
insbesondere in technischer Dokumentation ld.so genannt). Der
Programmlader lädt nun auch die benötigten Bibliotheken
automatisch. Im Kopf der Programmdateien steht eine Liste mit
diesen. Nach dem Laden bereitet er das Programm zum Start vor
und startet es letztendlich.
Dieser Vorgang findet bei fast allen Linux-Programmen statt. Nur
sehr wenige Programme verwenden keine dynamischen Bibliotheken.
Beispiele dafür sind login (hier aus
Sicherheitsgründen) und rpm (damit man es auch
starten kann, wenn die Systembibliotheken beschädigt oder defekt sind).
Um eine Bibliothek zu laden, bestimmt der Programmlader den
Namen der Bibliotheksdatei.
|
Jede Bibliothek hat natürlich einen Namen. So heißt
die Lib-C beispielsweise c und Mathematikfunktionen findet
man als m und die für das dynamische Laden heißt
dl (C-Programmierer scheinen sehr kurze Namen zu lieben).
Vor diese Namen wird lib vorangestellt, um kenntlich zu
machen, dass es sich um eine Bibliothek handelt. Dahinter schreibt man
bei gemeinsam benutzbaren Bibliotheken .so (für engl.:
shared object) und bei statisch linkbaren .a
(für engl.: archive).
Hinter das .so hängt man noch eine Versionsnummer an.
Diese Versionsnummer wird durch einen Punkt abgetrennt und kann
mehrwertig sein, so kann man beispielsweise eine
/lib/libdl.so.1.9.9 haben. Hierbei handelt es sich um die
dl in der Version 1.9.9.
Da die Bibliotheken die Versionsnummer im Dateinamen haben,
aber ein Programm in der Regel nicht an einer bestimmten Version
interessiert ist, werden symbolische Links angelegt (wie diese
Links entstehen, wird später noch beschrieben). So wird
beispielsweise die Datei libcrack.so.2.7 auch als
libcrack.so.2 und als libcrack.so
bekannt gemacht. Ein Programm kann nun gegen libcrack
gelinkt werden, und es wird auch noch funktionieren, wenn eine
libcrack.so.2.8 installiert wird, oder ein System nur
eine libcrack.so.2.6 anbietet. Linkt ein Programm direkt
gegen eine Version, so muss natürlich die genau passende vorhanden sein.
Dies ist mitunter beabsichtigt, kann aber bei Updates zu Problemen
führen, weil die Programme plötzlich nicht mehr gestartet werden können.
Oft funktionieren die Programme jedoch auch mit neueren Versionen.
Nun kann man
natürlich einfach einen Link per Hand erzeugen, der von dem betroffenen Programm
verwendet wird und auf eine vorhandene, neuere Version zeigt,
doch kann es auch hier zu Problemen kommen. Dieses Vorgehen
sollte daher in der Regel vermieden werden.
|
Werden die Bibliotheken bereits für das Starten eines Linuxsystems
benötigt, so werden sie in /lib installiert.
Andere, die zum Starten selbst noch nicht benötigt werden (zum
Beispiel Grafikbibliotheken) finden sich dagegen in /usr/lib.
Zusätzliche Bibliotheken, die nicht zu einer Distribution
gehören, sondern selbst installiert wurden, finden sich meistens
in /usr/local/lib.
|
Der Programmlader versucht zunächst, sämtliche Bibliotheken zu
laden. Er sucht dazu in den Pfaden, die in der Umgebungsvariablen
LD_LIBRARY_PATH hinterlegt sind. Anschließend wird
in einer Cache-Datei gesucht (/etc/ld.so.cache), welche
aus Effizienzgründen verwendet wird, und letztlich in
/usr/lib und /lib. Da die Verwendung
von LD_LIBRARY_PATH im Normalbetrieb umständlich ist,
wird diese normalerweise nicht gesetzt, vielmehr stehen alle Bibliotheken
in der Cache-Datei. Diese wird über ein spezielles Werkzeug erstellt. Fast
alle Bibliotheken werden über diesen Weg geladen.
Findet der Dynamische Linker nicht alle benötigen Bibliotheken
(oder fehlt eine Funktion oder ein anderes Symbol in einer
gefundenen Bibliothek), so wird der Start mit einer
Fehlermeldung abgebrochen.
|
Der Dynamische Linker wird über Umgebungsvariablen gesteuert.
Neben der bereits erwähnten Variable LD_LIBRARY_PATH
erkennt der Programmlader die Variable LD_PRELOAD.
Die durch Leerzeichen getrennten Einträge dieser Variable bilden eine Liste
von Bibliotheken, die auf jeden Fall zuerst geladen werden sollen.
Dies ermöglicht es, Bibliotheken zu laden, die Funktionen von
anderen Bibliotheken überschreiben. Der Linker verbindet die
Programmfunktionen in diesem Fall nämlich mit denen aus dieser
Bibliothek, selbst wenn später eine andere Bibliothek diese
Funktion ebenfalls definiert. Dies ist jedoch auch für Angriffe
ausnutzbar, so könnte man beispielsweise Bibliotheken
"unterschieben", die über Seiteneffekte von "normalen" Funktionen
bestimmte ungewollte Aktionen ausführen. Aus diesem Grund
ignoriert der Programmlader (beide) Variablen bei setuid
Programmen (also Programme, die unter anderen Benutzerrechten
laufen, als der Aufrufer besitzt). Dadurch kann ein Aufrufer sich
keine zusätzlichen Rechte verschaffen.
Eine Liste aller Umgebungsvariablen findet man in der Manpage
ld.so.
|
Die bereits erwähnte Cache-Datei wird vom Werkzeug
ldconfig erzeugt. Dieses verwendet eine
Konfigurationsdatei /etc/ld.so.conf.
Aus dem Namen dieser Datei geht hervor, dass ldconfig
und ld-linux.so eng zusammenarbeiten.
ldconfig sucht in den Verzeichnissen, die in
/etc/ld.so.conf stehen, nach Bibliotheken. Bei
diesem Vorgang werden auch die symbolischen Links angelegt, die
im Abschnitt "Namen von Bibliotheken" beschrieben wurden. Die
gefundenen Bibliotheken aus allen angegebenen Verzeichnissen werden
mit Versions- und weiteren Informationen in der Cache-Datei
/etc/ld.so.cache abgespeichert (welche dann vom
Programmlader verwendet wird).
Das Programm ldconfig lässt sich über
Kommandozeilenparameter steuern, die in der Manpage gelistet sind.
Ein Beispiel ist der Schalter -v, der etliche
Informationen anzeigt. Versuchen Sie doch einmal an dieser Stelle
einen Aufruf von ldconfig -v (als root) und sehen Sie sich die
Ausgabe an.
Aus naheliegenden Gründen verwendet ldconfig selbst
keine dynamischen Bibliotheken, sondern ist statisch gebunden.
|
|
|