|
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 Verzeichnisse /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 natürlich diese mitgeladen werden. Dazu wird
zunächst gar nicht das eigentliche Programm gestartet, sondern
der sogenannte Programm Lader
(eng: program loader). Dieser wird auch
dynamic linker genannt, da er die Bibliotheken zum
Programm bindet (engl: link). Auf Linuxsystemen heißt dieser
/lib/ld-linux.so.2 (die .2 ist wieder eine
Versionsnummer; das "-linux" zeigt, dass er Linuxspezifisch 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 Programm Lader 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 wird auch manchmal gemacht, was bei Updates zu Problemen führen
kann, 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
Programm verwendet wird, und auf eine vorhandene, neuere Version zeigt,
doch kann es auch hier zu Problemen kommen. Diese Vorgehen
sollte daher in Produktion vermieden werden.
|
Werden diese bereits für das Starten eines Linuxsystems
benötigt, so werden diese Bibliotheken 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 einem Cachefile gesucht (/etc/ld.so.cache), welches
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
im Cachefile. Dieses 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 Programm Lader die Variable LD_PRELOAD.
Die durch Leerzeichen getrennten Einträge dieser Variable ist 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 auch 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.
|
Das bereits erwähnte Cachefile wird vom Werkzeug
ldconfig erzeugt. Dieses verwendet eine
Konfigurationsdatei /etc/ld.so.conf. Erkennt man,
dass ldconfig und ld-linux.so
sehr stark zusammenarbeiten, wird auch der Name der Datei erkenntlich.
Indirekt konfiguriert man ja den dynamischen Linker (der ja
manchmal ld.so genannt wird).
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 im Cachefile
/etc/ld.so.cache abgespeichert (welches 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; ein Aufruf von ldconfig -v
ist vielleicht an dieser Stelle interessant.
Aus naheliegenden Gründen verwendet ldconfig selbst
keine dynamischen Bibliotheken, sondern ist statisch gebunden.
|
|
|