2012-05-21 26 views
11

Ich schreibe ein Werkzeug. Ein Teil dieses Tools ist seine Fähigkeit, die Parameter der Systemaufrufe zu protokollieren. Okay, ich kann ptrace für diesen Zweck verwenden, aber ptrace ist ziemlich langsam. Eine schnellere Methode, die mir in den Sinn kam, war das Glibc zu modifizieren. Aber das wird schwierig, da gcc magisch seine eigenen eingebauten Funktionen als Systemaufruf-Wrapper einfügt, anstatt den in glibc definierten Code zu verwenden. Auch die Verwendung von -fno-builtin hilft da nicht.Ist dies eine gute Möglichkeit, Systemaufrufe abzufangen?

Also kam ich auf diese Idee, eine Shared Library zu schreiben, die jeden Systemaufruf-Wrapper enthält, wie mmap und führen Sie dann die Protokollierung vor dem Aufruf der eigentlichen Systemaufruf-Wrapper-Funktion. Zum Beispiel ist der Pseudocode, wie mein mmap aussehen würde, unten angegeben.

int mmap(...) 
{ 
log_parameters(...); 
call_original_mmap(...); 
... 
} 

Dann kann ich LD_PRELOAD verwenden, um diese Bibliothek zuerst zu laden. Denkst du, dass diese Idee funktionieren wird, oder fehlt mir etwas?

+7

Es wird wahrscheinlich nicht für statisch verknüpfte ausführbare Dateien funktionieren. Und es wird nicht für ausführbare Dateien funktionieren, die syscalls ausführen, ohne durch libc zu gehen. –

+0

Möchten Sie jedes Mal abfangen, wenn ein tatsächlicher Sys-Aufruf ausgeführt wird (bei jedem "int 0x80") oder bei jedem Aufruf einer Library-Handler-Funktion? – Chris

+0

Ich denke, es wird wahrscheinlich langsam sein. Das ist genau das, was Valgrind für seine Instrumentierung tut, und obwohl es ein sehr bekanntes und entwickeltes Werkzeug ist, tötet es immer noch die Leistung. Ich denke, wenn es einen schnelleren Weg gäbe, wäre es schon dort benutzt worden. Meine Vermutung ist, dass Sie unterschätzen, wie viel die Protokollierungsfunktion kosten wird, und daran gibt es keinen Weg. – zebediah49

Antwort

0

Alle Systemaufrufe von User-Space durchlaufen einen Interrupt-Handler, um in den Kernel-Modus zu wechseln. Wenn Sie diesen Handler finden, können Sie dort wahrscheinlich etwas hinzufügen.

BEARBEITEN Ich fand diese http://cateee.net/lkddb/web-lkddb/AUDITSYSCALL.html. Linux Kernel: 2.6.6-2.6.39, 3.0-3.4 unterstützen die System Call Auditing. Dies ist ein Kernel-Modul, das aktiviert werden muss. Vielleicht können Sie die Quelle für dieses Modul anschauen, wenn es nicht zu verwirrend ist.

+2

LSM kann auch zur Steuerung von Systemaufrufen verwendet werden. http://en.wikipedia.org/wiki/Linux_Security_Modules – osgx

+0

Ich würde gerne hören, warum ich einen Downvote auf diese – Joelmob

+0

bekam Dies ist nicht allgemein zutreffend - es könnte für x86 auf bestimmten Versionen bestimmter Betriebssysteme, aber es gibt viele Plattformen und/oder Betriebssysteme, die keinen Interrupt als Übergangsmechanismus vom Benutzermodus zum Kernel verwenden. – twalberg

0

Wie andere bereits erwähnt haben, wird der dynamische Linker, wenn die Binärdatei statisch verknüpft ist, alle Versuche, Funktionen mit libdl abzufangen, überspringen. Stattdessen sollten Sie in Betracht ziehen, den Prozess selbst zu starten und den Einstiegspunkt zu der Funktion, die Sie abfangen möchten, umzuleiten.

Dies bedeutet, dass Sie den Prozess selbst starten, die Ausführung abfangen und den Speicher neu schreiben, um eine Sprunganweisung am Anfang der Definition einer Funktion im Speicher an eine neue Funktion zu übergeben, die Sie steuern.

Wenn Sie die tatsächlichen Systemaufrufe abfangen möchten und ptrace nicht verwenden können, müssen Sie entweder den Ausführungsort für jeden Systemaufruf finden und ihn neu schreiben, oder Sie müssen die Systemaufruftabelle im Speicher und überschreiben Ausfiltern alles außer dem Prozess, den Sie steuern möchten.

2

Keine Methode, die Sie sich im User-Space vorstellen können, funktioniert nahtlos mit jeder Anwendung. Zum Glück für Sie gibt es bereits Unterstützung für genau das, was Sie im Kernel machen wollen. Mit Kprobes und Kretprobes können Sie den Zustand der Maschine, der gerade vorausgeht und einem Systemaufruf folgt, untersuchen.

Dokumentation hier: https://www.kernel.org/doc/Documentation/kprobes.txt

0

Wenn der Code, den Sie entwickeln werden, ist prozessbedingte, manchmal kann man alternative Implementierungen entwickeln, ohne den vorhandenen Code zu brechen. Dies ist hilfreich, wenn Sie einen wichtigen Systemaufruf neu schreiben und ein voll funktionsfähiges System zum Debuggen wünschen.

Für Ihren Fall schreiben Sie den mmap() Algorithmus um, um eine aufregende neue Funktion zu nutzen (oder mit neuer Funktion zu erweitern). Wenn Sie beim ersten Versuch nicht alles richtig machen, ist es nicht einfach, das System zu debuggen: Ein nicht funktionierender mmap() - Systemaufruf führt mit Sicherheit zu einem nicht funktionierenden System. Wie immer gibt es Hoffnung.

Oft ist es sicher, den verbleibenden Algorithmus beizubehalten und Ihren Ersatz auf der Seite zu konstruieren.Sie können dies erreichen, indem die Benutzer-ID (UID) als bedingter mit dem mit welcher Algorithmus zu verwenden, um zu entscheiden:

if (current->uid != 7777) { 
/* old algorithm .. */ 
} else { 
/* new algorithm .. */ 
} 

Alle Benutzer außer UID 7777 wird die alte Algorithmus verwenden. Sie können einen speziellen Benutzer mit UID 7777 zum Testen des neuen Algorithmus erstellen. Dies macht es wesentlich einfacher, kritischen prozessbezogenen Code zu testen.

Verwandte Themen