- Informationen über alle Prozesse, auch über kurzlebige, sollten protokolliert werden.
- Wir sollten Informationen über den vollständigen Pfad zur ausführbaren Datei für alle laufenden Prozesse haben.
- Wir sollten unseren Code im Rahmen des Zumutbaren nicht für verschiedene Versionen des Kernels ändern oder neu kompilieren müssen.
- : - Kubernetes Docker, , / .
cgroup ID
. , , «» « ». , « », « », « », API, Docker . ID , . Docker .
Lassen Sie uns über gängige Linux-APIs sprechen, die bei dieser Aufgabe helfen können. Um die Geschichte nicht zu komplizieren, werden wir den Prozessen, die mit Systemaufrufen erstellt wurden, besondere Aufmerksamkeit widmen
execve
. Wenn wir über eine vollständigere Lösung des Problems sprechen, müssen während der Implementierung zusätzlich die mit Systemaufrufen fork/clone
und ihren Varianten erstellten Prozesse sowie die Ergebnisse der Aufrufe überwacht werden execveat
.
Einfache Lösungen im Benutzermodus implementiert
- Kontaktaufnahme
/proc
. Diese Methode ist aufgrund des Problems kurzlebiger Prozesse für uns nicht besonders geeignet. - netlink. netlink ,
PID
. ./proc
, . - Linux. — , . API . . . — , , , . , API ,
auditd
osquery
. , ,auditd
go-auditkann dieses Problem theoretisch abmildern. Bei Lösungen der Enterprise-Klasse können Sie jedoch nicht im Voraus wissen, ob und welche Kunden solche Tools verwenden. Es ist auch nicht möglich, im Voraus zu wissen, welche Sicherheitskontrollen, die direkt mit der Überwachungs-API arbeiten, von Clients verwendet werden. Der zweite Nachteil ist, dass die Überwachungs-APIs nichts über Container wissen. Und das trotz der Tatsache, dass dieses Thema seit vielen Jahren diskutiert wird.
Einfache Debugging-Tools im Kernel-Modus
Die Implementierung dieser Mechanismen beinhaltet die Verwendung von "Sonden" verschiedener Typen in einer einzigen Kopie.
RaceTracepoints
Tracepoints verwenden (
tracepoint
). Tracepoints sind Sensoren, die während der Kompilierung statisch an bestimmten Stellen im Kernel angeschlossen werden. Jeder dieser Sensoren kann unabhängig von den anderen aktiviert werden, wodurch Benachrichtigungen ausgegeben werden, wenn der Ort des Kernel-Codes erreicht und eingebettet wird. Der Kernel enthält mehrere für uns geeignete Tracepoints, deren Code an verschiedenen Stellen im Systemaufruf ausgeführt wird execve
. Diese - sched_process_exec
, open_exec
, sys_enter_execve
, sys_exit_execve
. Um diese Liste zu erhalten, habe ich den Befehl ausgeführtcat /sys/kernel/tracing/available_events | grep exec
und filterte die resultierende Liste unter Verwendung der Informationen, die beim Lesen des Kernel-Codes erhalten wurden. Diese Spurenpunkte passen besser zu uns als die oben beschriebenen Mechanismen, da sie es uns ermöglichen, die Beobachtung kurzlebiger Prozesse zu organisieren. Keiner von ihnen gibt jedoch Auskunft über den vollständigen Pfad zur ausführbaren Datei des Prozesses, wenn die Parameter exec
der relative Pfad zu einer solchen Datei sind. Mit anderen Worten, wenn der Benutzer einen Befehl wie ausführt cd /bin && ./ls
, erhalten wir die Pfadinformationen im Formular ./ls
, nicht im Formular /bin/ls
. Hier ist ein einfaches Beispiel:
# the sched_process_exec
sudo -s
cd /sys/kernel/debug/tracing
echo 1 > events/sched/sched_process_exec/enable
# ls
cd /bin && ./ls
# sched_process_exec
# ,
cd -
cat trace | grep ls
#
echo 0 > events/sched/sched_process_exec/enable
▍Kprobe / Kretprobe-Sensoren
Mit Sensoren
kprobe
können Sie Debug-Informationen von fast überall im Kernel extrahieren. Sie sind wie spezielle Haltepunkte im Kernel-Code, die Informationen liefern, ohne die Codeausführung zu stoppen. Ein Sensor kprobe
kann im Gegensatz zu Trackpoints mit einer Vielzahl von Funktionen verbunden werden. Der Code eines solchen Sensors wird während der Ausführung eines Systemaufrufs ausgelöst execve
. Aber ich habe im Aufrufdiagramm execve
keine Funktion gefunden, deren Parameter sowohl der PID
Prozess als auch der vollständige Pfad zu ihrer ausführbaren Datei sind. Infolgedessen haben wir das gleiche "relative Pfadproblem" wie bei der Verwendung von Tracepoints. Hier können Sie, basierend auf den Besonderheiten eines bestimmten Kernels, etwas "optimieren". Immerhin Sensorenkprobe
kann Daten aus dem Kernel-Aufrufstapel lesen. Eine solche Lösung funktioniert jedoch in verschiedenen Kernelversionen nicht stabil. Deshalb betrachte ich es nicht.
▍Verwenden von eBPF-Programmen mit Tracepoints mit kprobe- und kretprobe-Sonden
Hier geht es um die Tatsache, dass bei der Ausführung von Code Tracepoints oder Sensoren ausgelöst werden, aber der Code von eBPF-Programmen ausgeführt wird und nicht der Code von normalen Ereignishandlern.
Die Verwendung dieses Ansatzes eröffnet uns einige neue Möglichkeiten. Jetzt können wir beliebigen Code im Kernel ausführen, wenn wir einen Systemaufruf ausführen
execve
. Dies sollte uns theoretisch die Möglichkeit geben, alle benötigten Informationen aus dem Kernel zu extrahieren und an den Benutzerbereich zu senden. Es gibt zwei Möglichkeiten, um diese Art von Daten abzurufen, aber keine erfüllt die oben genannten Anforderungen.
- ,
task_struct
linux_binprm
. , , . ,sched_process_exec
, eBPF- , dentrybprm->file->f_path.dentry
, . eBPF- . . , eBPF- , , , . - eBPF . , . — API. — . (, eBPF,
cgroup ID
, ).
«»
-
LD_PRELOAD
exec
libc
. , . , , , , . -
execve
,fork/clone
chdir
, . ,execve
execve
. — eBPF- eBPF- , . - ,
ptrace
. -. —ptrace
seccomp
SECCOMP_RET_TRACE
.seccomp
execve
,execve
seccomp
execve
. - Verwenden von AppArmor. Sie können ein AppArmor-Profil schreiben, um zu verhindern, dass Prozesse ausführbare Dateien aufrufen. Wenn Sie dieses Profil im Trainingsmodus verwenden (Beschwerde), verbietet AppArmor nicht die Ausführung von Prozessen, sondern gibt nur Benachrichtigungen über Verstöße gegen die im Profil angegebenen Regeln aus. Wenn wir ein Profil mit jedem laufenden Prozess verbinden, erhalten wir eine funktionierende, aber sehr unattraktive und zu "hackige" Lösung. Es lohnt sich wahrscheinlich nicht, diesen Ansatz zu verwenden.
Andere Lösungen
Ich werde sofort sagen, dass keine dieser Lösungen unseren Anforderungen entspricht, aber ich werde sie trotzdem auflisten:
- Verwenden des Dienstprogramms
ps
. Dieses Tool adressiert einfach/proc
und leidet infolgedessen unter den gleichen Problemen wie das Weiterleiten an/proc
. - execsnoop, eBPF. , , ,
kprobe/kretprobe
, , , . ,execsnoop
, , , . -
execsnoop
, eBPF. —kprobe
, .
In Zukunft wird es möglich sein, die noch nicht verfügbare eBPF- Hilfsfunktion get_fd_path zu verwenden . Nachdem es dem Kernel hinzugefügt wurde, ist es hilfreich, um unser Problem zu lösen. Der vollständige Pfad zur ausführbaren Datei des Prozesses muss mit einer Methode ermittelt werden, die keine Informationen aus den Kerneldatenstrukturen liest.
Ergebnis
Keine der von uns überprüften APIs ist perfekt. Im Folgenden möchte ich einige Empfehlungen geben, mit welchen Ansätzen Informationen über Prozesse abgerufen werden sollen und wann sie verwendet werden sollen:
- —
auditd
go-audit. , . , , , . , , , - API , , . — , . - , , , , ,
execsnoop
. — . - , , , , , . , . , , eBPF- eBPF-,
perf
... Eine Geschichte über all dies verdient einen separaten Artikel. Das Wichtigste, das Sie bei der Auswahl dieser Methode zur Überwachung von Prozessen beachten sollten, ist Folgendes. Wenn Sie eBPF-Programme verwenden, prüfen Sie die Möglichkeit ihrer statischen Kompilierung, damit Sie nicht von den Kernel-Headern abhängig sind. Aber genau diese Abhängigkeit versuchen wir mit dieser Methode zu vermeiden. Die Verwendung dieser Methode bedeutet auch, dass Sie nicht mit Kernel-Datenstrukturen arbeiten können und keine Frameworks wie BCC verwenden können , die eBPF-Programme zur Laufzeit kompilieren. - Wenn Sie nicht an kurzlebigen Prozessen interessiert sind und die vorherigen Empfehlungen nicht zu Ihnen passen, verwenden Sie die Netlink-Funktionen zusammen mit
/proc
.
Wie organisieren Sie die Überwachung laufender Prozesse unter Linux?