
Ein Kernelspace-Syscall-Interceptor und randomisierter Fehlerinduzierer
KRF ist ein Kernelspace-Randomized-Faulter.
Es unterstützt derzeit die Linux- und FreeBSD-Kernel.
Fehlerinjektion ist eine Software-Testtechnik, bei der Fehler ("Faults") in den von einem Programm aufgerufenen Funktionen ausgelöst werden. Wenn der Aufgerufene keine ordnungsgemäße Fehlerprüfung und -behandlung durchgeführt hat, können diese Fehler zu unzuverlässigem Anwendungsverhalten oder ausnutzbaren Sicherheitslücken führen.
Im Gegensatz zu den vielen Userspace-Fehlerinjektionssystemen da draußen läuft KRF im Kernelspace über ein geladenes Modul. Dies hat mehrere Vorteile:
LD_PRELOAD zur Injektion angewiesen ist.syscall(3) oder Inline-Assembly erfolgen.dlsym.Es gibt auch mehrere Nachteile:
cr0 herumdreht. Es gibt wahrscheinlich
eine architekturunabhängige Methode, das in Linux zu tun, irgendwo.KRF überschreibt die Systemcall-Tabelle von Linux oder FreeBSD: Wenn über krfctl konfiguriert, ersetzt KRF fehleranfällige
Syscalls durch dünne Wrapper.
Jeder Wrapper führt dann eine Prüfung durch, ob der Aufruf fehlerhaft sein soll, unter Verwendung eines konfigurierbaren Zielsystems, das eine bestimmte personality(2), PID, UID und/oder GID anvisieren kann. Wenn der Prozess nicht fehlerhaft sein soll, wird der ursprüngliche Syscall
aufgerufen.
Schließlich wird der anvisierte Aufruf durch eine zufällige Fehlerfunktion fehlerhaft gemacht. Beispielsweise
könnte ein read(2)-Aufruf einen von EBADF, EINTR, EIO usw. erhalten.
Weitere Details zur Implementierung von KRF finden Sie in unserem Blogbeitrag.
HINWEIS: Wenn Sie Vagrant haben, verwenden Sie einfach die Vagrantfile und springen Sie zu den Build-Schritten.
KRF sollte mit jedem relativ aktuellen (4.15+) Linux-Kernel mit CONFIG_KALLSYMS=1 funktionieren.
Dies schließt den Standard-Kernel auf Ubuntu 18.04 und wahrscheinlich vielen anderen aktuellen Distributionen ein.
HINWEIS: Ignorieren Sie dies, wenn Sie Vagrant verwenden.
Abgesehen von einer C-Toolchain (GCC ist für Linux wahrscheinlich notwendig) sind KRFs einzige Abhängigkeiten
libelf, die Kernel-Header und Ruby (>=2.4, für die Codegenerierung).
GNU Make ist auf allen Plattformen erforderlich; FreeBSD benötigt zusätzlich BSD Make.
Für Systeme mit apt:
sudo apt install gcc make libelf-dev ruby linux-headers-$(uname -r)
git clone https://github.com/trailofbits/krf && cd krf
make -j$(nproc)
sudo make install # Installiert Modul nach /lib/modules und Werkzeuge nach /usr/local/bin
sudo make insmod # Lädt Modul
oder, wenn Sie Vagrant verwenden:
git clone https://github.com/trailofbits/krf && cd krf
vagrant up linux && vagrant ssh linux
# innerhalb der VM
cd /vagrant
make -j$(nproc)
sudo make install # Installiert Modul nach /lib/modules und Werkzeuge nach /usr/local/bin
sudo make insmod # Lädt Modul
oder, für FreeBSD:
git clone https://github.com/trailofbits/krf && cd krf
vagrant up freebsd && vagrant ssh freebsd
# innerhalb der VM
cd /vagrant
gmake # NICHT make!
gmake install-module # Installiert Modul nach /boot/modules/
sudo gmake install-utils # Installiert Werkzeuge nach /usr/local/bin
gmake insmod # Lädt Modul
KRF hat drei Komponenten:
krfx)krfexec)krfctl)krfmesg)Um das Kernel-Modul zu laden, führen Sie make insmod aus. Um es zu entladen, führen Sie make rmmod aus.
Bei der ersten Verwendung kann es hilfreich sein, sudo krfmesg in einem separaten Terminal zu starten, um von krfx protokollierte Nachrichten zu sehen.
KRF beginnt in einem neutralen Zustand: Es werden keine Syscalls abgefangen oder fehlerhaft gemacht, bis der Benutzer
ein Verhalten über krfctl festlegt:
# keine induzierten Fehler, selbst wenn KRF geladen ist
ls
# weisen Sie krf an, read(2)- und write(2)-Aufrufe fehlerhaft zu machen
# beachten Sie, dass krfctl Root-Rechte benötigt
sudo krfctl -F 'read,write'
# weisen Sie krf an, jedes Programm fehlerhaft zu machen, das von
# krfexec gestartet wird, also eine Personality von 28
sudo krfctl -T personality=28
# kann fehlerhaft sein!
krfexec ls
# weisen Sie krf an, mit einer Wahrscheinlichkeit von 1/100 (oder 1%) fehlerhaft zu machen
# beachten Sie, dass dieser Wert als Kehrwert dargestellt wird,
# z. B. bedeutet 1, dass alle fehleranfälligen Syscalls fehlerhaft werden
# und 500 bedeutet, dass im Durchschnitt alle 500 Syscalls einer fehlerhaft wird (1/500 oder 0,2%)
sudo krfctl -p 100
# weisen Sie krf an, das `io`-Profil fehlerhaft zu machen (also E/A-bezogene Syscalls)
sudo krfctl -P io
# krfexec übergibt Optionen ebenfalls korrekt
krfexec echo -n 'kein Zeilenumbruch'
# löschen der Fehlerspezifikation
sudo krfctl -c
# löschen der Zielvorgabenspezifikation
sudo krfctl -C
# keine induzierten Fehler, da keine Syscalls fehlerhaft gemacht werden
krfexec firefox
HINWEIS: Die meisten Benutzer sollten krfctl anstelle der manuellen Bearbeitung dieser Dateien verwenden.
Unter FreeBSD sind diese Werte über sysctl krf.whatever anstelle von procfs zugänglich.
/proc/krf/rng_stateDiese Datei erlaubt es einem Benutzer, den internen Zustand des PRNG von KRF zu lesen und zu ändern.
Zum Beispiel wird jeder der folgenden Befehle den Zustand korrekt aktualisieren:
echo "1234" | sudo tee /proc/krf/rng_state
echo "0777" | sudo tee /proc/krf/rng_state
echo "0xFF" | sudo tee /proc/krf/rng_state
Der Zustand ist eine 32-Bit-ganze Zahl ohne Vorzeichen; ein Änderungsversuch darüber hinaus schlägt fehl.
/proc/krf/targetingDiese Datei erlaubt es einem Benutzer, die von KRF für das Syscall-Targeting verwendeten Werte festzulegen.
HINWEIS: KRF verwendet standardmäßig eine Personality, die vom Linux-Kernel standardmäßig nicht verwendet wird. Wenn Sie diese
ändern, sollten Sie darauf achten, dass Sie nichts verwenden, das für Linux relevant ist. man 2 personality
enthält die Details.
echo "0 28" | sudo tee /proc/krf/targeting
Eine Personality von 28 ist in krfexec fest codiert und muss gesetzt werden, damit von krfexec ausgeführte Dinge
fehlerhaft gemacht werden.
/proc/krf/probabilityDiese Datei erlaubt es einem Benutzer, die Wahrscheinlichkeit der Fehlerinduktion für einen bestimmten (fehleranfälligen) Syscall zu lesen und zu schreiben.
Die Wahrscheinlichkeit wird als Kehrwert dargestellt, z. B. bedeutet 1000, dass im Durchschnitt 0,1% der
fehleranfälligen Syscalls fehlerhaft gemacht werden.
echo "100000" | sudo tee /proc/krf/probability
/proc/krf/controlDiese Datei steuert die Syscalls, die KRF fehlerhaft macht.
HINWEIS: Die meisten Benutzer sollten krfctl anstelle der direkten Interaktion mit dieser Datei verwenden —
Ersteres führt die Übersetzung von Syscall-Namen in Nummern automatisch durch und liefert klarere
Fehlermeldungen, wenn etwas schiefgeht.
# Ersetzt den Syscall in Slot 0 (normalerweise SYS_read) durch seinen fehlerhaften Wrapper
echo "0" | sudo tee /proc/krf/control
Wenn eine Zahl größer als KRF_NR_SYSCALLS übergeben wird, veranlasst KRF das Leeren der gesamten Syscall-Tabelle
und kehrt in den neutralen Zustand zurück. Da KRF_NR_SYSCALLS nicht unbedingt für beliebige
Versionen des Linux-Kernels vorhersagbar ist, ist die Wahl einer großen Zahl (wie 65535) in Ordnung.
Wenn eine gültige Syscall-Nummer übergeben wird, für die kein Fehlerinjektions-Wrapper existiert, schlägt das write(2)
auf die Datei mit EOPNOTSUPP fehl.
/proc/krf/log_faultsDiese Datei steuert, ob KRF Kernel-Logs bei fehlerhaften Syscalls ausgibt. Standardmäßig werden keine Logging-Nachrichten ausgegeben.
HINWEIS: Die meisten Benutzer sollten krfctl anstelle der direkten Interaktion mit dieser Datei verwenden.
# Fehler-Logging aktivieren
echo "1" | sudo tee /proc/krf/log_faults
# Fehler-Logging deaktivieren
echo "0" | sudo tee /proc/krf/log_faults
# den Logging-Status lesen
cat /proc/krf/log_faults
ENOMEM).
personality(2)-Wert möglich sein.Vielen Dank an Andrew Reiter für den ersten Port von KRF nach FreeBSD. Andrews Arbeit wurde im Auftrag der Applied Research Group bei Veracode durchgeführt.
KRF ist unter den Bedingungen der GNU GPLv3 lizenziert.
Siehe die Datei LICENSE für die genauen Bedingungen.