SelfLinux Programmierung Bibliotheken Abschnitt 3 | SelfLinux-0.13.0

| Bibliotheken | Autor Formatierung GFDL

#### 5 Gemeinsam genutzte, dynamisch gelinkte Bibliotheken

#### 5.1 Verwenden von Bibliotheken

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.

#### 5.2 Der Linux Programmlader

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.

#### 5.3 Namen von Bibliotheken

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.

#### 5.4 Platzierung im Dateisystem

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.

#### 5.5 Funktion des Dynamischen Linkers (Programmladers)

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.

#### 5.6 Umgebungsvariablen

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.

#### 5.7 Cache-Datei erzeugen

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.