Auf einem x86-System habe ich ein Linux-Kernel-Modul ("Watcher-Modul"), das vom Kernel jedes Mal benachrichtigt wird, wenn ein bestimmtes Kernel-Modul ("target") geladen wird. Fast jedes Kernel-Modul kann ein Ziel sein. Ich verwende dies in einem Instrumentierungssystem an dem ich arbeite.
Wenn das Überwachungsmodul eine solche Benachrichtigung behandelt, könnte es aus irgendeinem Grund nützlich sein, wenn der Beobachter die Adressen von ELF-Abschnitten des geladenen Zielmoduls kannte. Irgendwelche Ideen, wie diese Information im Kernelraum erhalten werden könnte?
Natürlich könnte ich wahrscheinlich den Inhalt der entsprechenden Dateien in /sys/module/<target_name>/sections/
im Userspace bekommen, sobald das Ziel geladen ist und dann diese Daten irgendwie an das Watcher-Modul weitergeben, aber das ist zu ungeschickt. Ich möchte einen Weg finden, diese Information direkt im Kernelraum zu erhalten.
Soweit ich in den Quellen des Modulladeprogramms gesehen habe, speichert es keine Abschnittsadressen in struct module
, sondern erstellt nur sysfs-Dateien für die Abschnitte. Kann es sein, dass man irgendwie die Kernel-Objekte findet, die diesen Dateien entsprechen und die benötigten Daten von diesen Objekten lesen? Oder verwenden Sie wahrscheinlich einen anderen Ansatz?
Nachdem ich geforscht habe, wie die Informationen über die Abschnitte eines Moduls in sysfs gelangen, habe ich keine Möglichkeit gefunden, es abzurufen, ohne die internen Strukturdefinitionen des Kernels zu verwenden. Die Verwendung solcher Dinge ist in meinem Projekt keine Option, deshalb habe ich endlich einen anderen Ansatz implementiert, der hoffentlich zuverlässiger ist.
Kurz gesagt, die Idee ist wie folgt. Mein Kernelmodul verwendet die Benutzermodus-Hilfs-API, um einen User-Space-Prozess zu starten (eine Shell, die mein Skript tatsächlich ausführt). Dieser Prozess erhält den Namen des Kernelmoduls "target" als Parameter und sammelt die Informationen über seine Abschnitte von sysfs ( /sys/module/<target_name>/sections/
). Aus dem Benutzerraum können diese Informationen leicht erhalten werden. Danach übergibt es die gesammelten Daten über eine Datei in debugfs als String an mein Kernelmodul. Das Modul analysiert die Zeichenfolge und validiert deren Inhalt. Wenn alles in Ordnung ist, werden die Namen und Startadressen der ELF-Abschnitte verfügbar sein.
Ich gebe zu, der Trick mit dem Benutzer-Modus-Helfer ist ziemlich schwerfällig, aber er erledigt die Aufgabe.
Ich habe eine Beispielimplementierung des oben beschriebenen Ansatzes vorbereitet - siehe Beispiel "Abschnitte" .
Details zur Benutzermodus-Hilfsprogramm-API finden Sie in den Quellcodes in <linux/kmod.c>
und <linux/kmod.h>
, nämlich in der Definition von call_usermodehelper()
. Die Beispiele sowie die Erläuterung der typischen Verwendung der API finden Sie in Dieser Artikel .
Beachten Sie, dass die Beispiele aus diesem Artikel eine sind Bit ungenau: Die Init-Funktion des Moduls gibt dort das Ergebnis von call_usermodehelper()
zurück. Letzteres gibt jedoch einen 2-Byte-Statuscode zurück (zumindest wenn er mit UMH_WAIT_PROC
aufgerufen wurde) und nicht 0 oder einen negativen Fehlercode, von dem erwartet wird, dass die init-Funktion zurückkehrt. Dies kann zu Laufzeitwarnungen führen. Was call_usermodehelper()
tatsächlich zurückgibt, wird hier erklärt.
Die Datei linux / kernel / module.c hat einige nicht statische Funktionen (aber ohne dieses EXPORT_SYMBOL im Vordergrund) wie module_address_lookup (), aber diese Funktionen verwenden Dinge wie preempt_disable () und _enable (). Ich würde diese Funktionen lieber nicht verwenden und würde stattdessen vorschlagen, sysfs-interface zu verwenden, obwohl sich der Treiber bereits im Kernel-Modus befindet.
Tags und Links x86 kernel linux-kernel kernel-module