Xz: Das eine Zeichen, das Linux Landlock außer Kraft setzte
(git.tukaani.org)- Die Änderung an CMakeLists.txt in xz.git ist ein Fall, in dem bei der Umstellung der Landlock-Sandbox-Erkennung von einer Prüfung auf das Vorhandensein des Headers auf einen echten Kompilierungstest ein einzelnes
.-Zeichen im Testcode landete - Die neue Prüfung wurde hinzugefügt, um Systeme auszufiltern, die zwar
linux/landlock.hhaben, denen aber die nötigen syscall-Definitionen fehlen könnten - Der Kompilierungstest bindet
<linux/landlock.h>,<sys/syscall.h>und<sys/prctl.h>ein und referenziertprctl,SYS_landlock_create_ruleset,SYS_landlock_restrict_selfsowieLANDLOCK_CREATE_RULESET_VERSION - Das bisherige Kriterium
HAVE_LINUX_LANDLOCK_Hwird in HAVE_LINUX_LANDLOCK geändert; auch die Einstellungen fürSANDBOX_COMPILE_DEFINITIONundSANDBOX_FOUNDfolgen diesem Ergebnis - Der Commit korrigiert den Linux-Landlock-Feature-Test in den Autotools- und CMake-Builds; der bereitgestellte Diff zeigt die Änderung auf der CMake-Seite
Änderung der Landlock-Erkennung in CMake
- Die betroffene Datei ist CMakeLists.txt in xz.git; die Änderung befindet sich im Block
# Sandboxing: Landlock - Die bisherige CMake-Logik prüfte, wenn
ENABLE_SANDBOXaufONoderlandlockstand undSANDBOX_FOUNDnicht gesetzt war, mitcheck_include_file(linux/landlock.h HAVE_LINUX_LANDLOCK_H)lediglich das Vorhandensein des Headers - Nach der Änderung wird mit
check_c_source_compilesein kleines C-Programm tatsächlich kompiliert, um zu prüfen, ob Landlock nutzbar ist- Manche Systeme besitzen zwar
linux/landlock.h, haben aber möglicherweise nicht die für Linux Landlock nötigen syscall-Definitionen - Der Testcode bindet
<linux/landlock.h>,<sys/syscall.h>und<sys/prctl.h>ein - In
my_sandbox()referenziert erprctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0),SYS_landlock_create_ruleset,SYS_landlock_restrict_selfundLANDLOCK_CREATE_RULESET_VERSION
- Manche Systeme besitzen zwar
Einzelnes Zeichen und Änderung des Variablennamens
- Nach dem Include-Block des eingefügten Kompilierungstest-Codes steht eine einzelne Zeile mit
. - Die Ergebnisvariable wird von
HAVE_LINUX_LANDLOCK_Hin HAVE_LINUX_LANDLOCK geändert - Auch die Bedingung wird von
if(HAVE_LINUX_LANDLOCK_H)zuif(HAVE_LINUX_LANDLOCK)geändert - Der Wert von
SANDBOX_COMPILE_DEFINITIONverwendet statt"HAVE_LINUX_LANDLOCK_H"nun"HAVE_LINUX_LANDLOCK" - Die anschließende Einstellung
SANDBOX_FOUND ONbleibt erhalten
1 Kommentare
Meinungen auf Hacker News
Antwort: https://git.tukaani.org/?p=xz.git;a=commitdiff;h=f9cf4c05edd...
Wer das Landlock-Zugriffskontrollsystem von Linux nicht gut kennt, findet hier eine Erklärung: https://docs.kernel.org/userspace-api/landlock.html
Die offizielle (vermutlich ...) Incident-Response-Seite zu xz: https://tukaani.org/xz-backdoor/
Aber wegen eines kleinen Punkts, der nahe am linken Rand des Diffs klebte und deshalb schwer zu erkennen war, wurde der C-Code immer ungültig, sodass Landlock immer deaktiviert blieb?
Beeindruckend niederträchtig und niederträchtig beeindruckend. Beim ersten Lesen habe ich es auch nicht gesehen
Wenn man etwas verstecken will, gibt es bessere Methoden, etwa Unicode-Doppelgänger auszutauschen. Manche sehen je nach Schriftart bis aufs Pixel gleich aus
Vielleicht habe ich den Faden verloren, aber ist die Absicht hier schon bewiesen?
Beim vorsichtigen Überfliegen sah ich an einer Stelle, an der definitiv keiner sein sollte, einen Punkt und dachte: „So schwer ist es ja gar nicht“
Dann tippte ich gegen den Bildschirm, und der Punkt bewegte sich
Verdammter Monitorstaub
Ich kann nicht glauben, dass Systemsicherheit von einer so lockeren Kette der Korrektheit abhängt. Es gab jede Menge Stellen, an denen man das hätte verhindern können
+ # A compile check is done here because some systems have+ # linux/landlock.h, but do not have the syscalls defined+ # in order to actually use Linux Landlock.Man sollte die Header solcher Systeme reparieren, damit sie explizit ausgeschlossen werden. Was bringt ein Header, wenn er seine eigene Funktionalität nicht deklariert?
Und ich verstehe auch nicht, warum es nach der Erstellung des Binary Blob (selbst wenn er aus Open Source kompiliert wurde) keinen einzigen Test gibt, der prüft, ob die Sicherheit intakt ist
Eine Website-Zahlungsfunktion würde man auch nicht ohne End-to-End-Tests für die Kernfunktionalität ausrollen. Es scheint eine Prioritätenverschiebung zu geben, bei der neue Funktionen vor Stabilität stehen
Ich hoffe, der Fix besteht nicht einfach darin, den
.zu entfernen. Habe gerade in einem anderen HN-Beitrag gesehen, wie das Entfernen des.gezeigt wurdeEine Header-Korrektur oder zusätzliche Tests hätten das nicht verhindert. Es gab zunächst kein Anzeichen dafür, dass der Header kaputt war, und zusätzliche Tests hätten auf andere Weise manipuliert oder im Release-Tarball ignoriert werden können
[1] https://git.tukaani.org/?p=xz.git;a=commit;h=328c52da8a2bbb8...
Da Nutzer möglicherweise mit GCC 9.4.0 kompilieren wollten und die von diesem Header abhängige Funktion für die Anwendung nicht zentral war, deaktivierte der Build diese Funktion einfach und gab eine Warnung aus, wenn er erkannte, dass der Header kaputt war
Zurück zu xz: Wenn Sicherheit nicht die oberste Priorität ist, wirkt es durchaus vernünftig, den Ausfall einer optionalen Funktion zu ignorieren und weiterzumachen. Im Nachhinein ist es natürlich leicht, mit dem Finger darauf zu zeigen, aber ohne diesen Kontext ist die Entscheidung nicht völlig unsinnig
Uff, sein letzter Commit verschlechtert die Sicherheitsmeldungen: https://git.tukaani.org/?p=xz.git;a=commitdiff;h=af071ef7702...
Wofür bzw. wie sollte Landlock eigentlich eingesetzt werden?
In einer allgemeinen Bibliothek wie für Komprimierung/Dekomprimierung dürfte es in der Praxis schwer nutzbar sein. Eine Bibliothek kann nicht wissen, was das Programm tun soll und was eingeschränkt werden muss.
Bei einem Programm kann das klarer sein.
Der Angriff auf sshd nutzte liblzma als Bibliothek. Dann scheint das Abschalten von Landlock irrelevant zu sein, oder? Ist das ein Hinweis darauf, dass es noch weiteren, bisher nicht entdeckten Schadcode gibt, oder dass geplant war, ihn später einzubauen?
Wenn Landlock entfernt wird, sperrt sich der Daemon nicht selbst, sodass die Ausführung der Payload leichter wird, sobald die Ausnutzungsphase erreicht ist.
Ich sehe die beiden Dinge nicht als unabhängig. Man hatte wohl bereits eine Payload im Blick und merkte, dass dies ein Hindernis werden würde.
Dieser Vorfall ist sehr verwirrend. Manche Teile sind fast unglaublich raffiniert, andere wirken ziemlich schlampig.
Die Idee ist, dass die Bibliothek komplexe Arbeit in einem separaten Thread startet und der User-Code innerhalb der aufgerufenen API auf diesen Thread wartet. Der Thread wendet selbst Landlock an und beginnt dann mit der Arbeit. Wenn etwas schiefläuft, ist der Code isoliert.
In diesem Fall funktioniert das natürlich nicht, weil die Sandbox vom Angreifer kontrolliert wird. Er kann sie einfach abschalten oder schwächer machen als ursprünglich. Trotzdem kann man es auch auf andere Weise umsetzen.
Was genau war hier eigentlich das Ziel? Wollte man später weitere Backdoors einbauen, plausibler abstreitbare Backdoors? Aus meiner Sicht hätten weder oss-fuzz noch diese Änderung die entdeckte Backdoor tatsächlich gefunden.
Aber warum alle Backdoor-Eier in einen Korb legen, also in eine einzige Bibliothek?
Außerdem wird nicht die Bibliothek selbst backdoored, sondern ein Tool angegriffen, das sie verwendet. Ganz im Stil von „Reflections on trusting trust“.
Bis zum Scheitern klang das nach einem perfekten Plan.
Ich frage mich, warum es nützlich war, zu verhindern, dass Landlock in xz aktiviert wird. Wollte man in einer späteren Phase schädliche Inhalte in xz-Archive einschleusen? Wenn ja, warum nicht einfach direkt schädliches Verhalten in xz einbauen?
In ein gewartetes C-Projekt heimlich einen Buffer Overflow oder Use-after-free einzubauen, könnte unbemerkt möglich sein. Einen echten Trojaner auszuliefern ist deutlich schwieriger, und bei der xz-zu-sshd-Backdoor hat sich genau das gezeigt.
Das ist überraschend auffällig. Die Technik zum Abschalten der Funktion ist clever, und der Commit wirkt ziemlich plausibel. Aber warum wurde statt eines einfachen Tippfehlers ein offensichtlicher Syntaxfehler gewählt? Hätte man es zum Beispiel bemerkt, wenn der Fehler
PR_SET_NO_NEW_PRIVgewesen wäre?Das wäre auch leichter abstreitbar gewesen.
Nebenbei hat dieses Malware-Team einen hervorragenden Datensatz geschaffen, um KI darauf zu trainieren, Sicherheitsprobleme zu erkennen. Jeder Commit enthält ein Sicherheitsproblem, und die Open-Source-Community wird sie der Reihe nach durchgehen und finden.
Danke an die Maintainer, die die Aufräumarbeit leisten. Das ist sicher keine spaßige Aufgabe.
Deshalb mag ich configure-artige Build-Systeme, die automatisch Funktionen ein- und ausschalten, wirklich nicht. Wenn ich etwas will, möchte ich es explizit aktivieren. Wenn es gute Gründe gibt, eine Funktion standardmäßig zu aktivieren, sollte man sie stattdessen explizit deaktivieren können.
Man sollte einfach ein Standard-Feature-Set haben und nach Bedarf
--enable-a --disable-berlauben.Dass Bugs im Prüfprozess stillschweigend geschluckt werden, ist noch ein anderes Problem.