Wie mein minimaler speichersicherer Go-rsync Schwachstellen vermeidet
(michael.stapelberg.ch)- gokrazy/rsync ist eine minimale rsync-Implementierung in Go und wurde anhand von 12 rsync-Schwachstellen geprüft, die im Januar 2025 und Mai 2026 veröffentlicht wurden
- Go-Bounds-Checks und Nullinitialisierung machen aus Heap-Overflows und Stack-Informationslecks entweder einen Panic oder harmlose Werte, wobei ein Panic weiterhin zu einer Denial-of-Service-Situation führen kann
- Bei Pfadtraversal- und TOCTOU-Klassen sind traversal-resistente Datei-APIs wie os.Root aus Go 1.24 die zentrale Abwehr; gokrazy/rsync wurde vollständig darauf umgestellt
- Die Strategie einer minimalen Implementierung vermeidet Schwachstellen in nicht implementierten Funktionen wie
--inc-recursive, Komprimierung,--safe-links, Proxys und Hostname-ACLs und reduziert so die Angriffsfläche - Die meisten Schwachstellen entstanden durch fehlende Validierung und übermäßige Komplexität; für einfache Anwendungsfälle kann eine einfache Implementierung besser geeignet sein
Hintergrund und Umfang
- Im Januar 2025 veröffentlichten mehrere Sicherheitsforscher insgesamt 6 Sicherheitslücken im Upstream-Samba-rsync, von denen einige beliebige Codeausführung und Dateiexfiltration ermöglichen
- Ein zentraler Prüfpunkt ist, ob gokrazy/rsync, eine kompatible minimale Implementierung in Go, solche Schwachstellenklassen tatsächlich vermeiden kann
- Gegenstand der Analyse sind 12 Schwachstellen aus der Charge vom Januar 2025 und der Charge vom Mai 2026 zusammen
- Wer Upstream-rsync in Produktion betreibt, sollte auf 3.4.3 oder neuer aktualisieren; gokrazy/rsync sollte auf v0.3.3 oder neuer angehoben werden
- gokrazy/rsync wurde geschrieben, um Softwarepakete des Linux-Distributionsforschungsprojekts distri in router7 bereitzustellen; router7 basiert auf der Go-Appliance-Plattform gokrazy
- Anfangs gab es nur einen rsync-Server, inzwischen werden aber alle Richtungen unterstützt, und die grundlegenden rsync-Funktionen zum Einbinden in Go-Programme werden in mehreren gokrazy/rsync-Servern verwendet
Schwachstellen im Januar 2025
-
CVE-2024-12084: Heap-Buffer-Overflow, Schweregrad 9,8
- rsync verglich die aus dem Netzwerk empfangene Prüfsummenlänge mit
MAX_DIGEST_LEN, verwendete intern jedoch immer den 16-Byte-Pufferchar sum2[SUM_LENGTH] MAX_DIGEST_LENkann größer werden, wenn Unterstützung für SHA256- oder SHA512-Prüfsummen einkompiliert ist, sodass ein Angreifer die Grenze des Pufferssum2um bis zu 48 Byte überschreiben konnte- Das Problem wurde im September 2022 mit Commit
ae16850eingeführt, der Unterstützung für SHA256/SHA512-Prüfsummen hinzufügte - Der upstream-Fix ersetzte
sum2durch das dynamisch allokiertesum2_arrayund korrigierte Allokation und Prüfung anhand der Prüfsummenlänge des Übertragungsalgorithmusxfer_sum_len - In Go führt eine fehlerhafte Bounds-Prüfung nicht zu einem Heap-Buffer-Overflow; stattdessen löst die Laufzeit mit ihrer Bounds-Prüfung eine Panic aus
- Auch in gokrazy/rsync fehlte eine Validierung des Summen-Headers, es handelte sich aber nicht um eine Größenverwechslung; setzt man
ChecksumLengthauf512, erzeugt die Go-Laufzeitpanic: runtime error: slice bounds out of range [:512] with length 16 - Da ein kompletter Serverabsturz kein wünschenswerter Fehlermodus ist, wurde die fehlende Bounds-Prüfung ergänzt und die Panic in einen Fehler umgewandelt
- rsync verglich die aus dem Netzwerk empfangene Prüfsummenlänge mit
-
CVE-2024-12085: Umgehung von ASLR durch Preisgabe von Stack-Informationen, Schweregrad 7,5
- Wegen derselben fehlenden Validierung wie bei CVE-2024-12084 konnte ein Angreifer einen kurzen Prüfsummenalgorithmus auswählen und anschließend behaupten, eine längere Prüfsumme gesendet zu haben
- Laut dem Google Security report kann die Kombination aus Heap-Buffer-Overflow und Informationsleck dazu führen, dass ein Client mit nur anonymem Lesezugriff beliebigen Code auf der rsync-Servermaschine ausführt
hash_search()erzeugte den Chunk-Digest im Stack-Pufferchar sum2[MAX_DIGEST_LEN]und verglich ihn mitmemcmp(), aber der lokale Stack-Puffersum2wurde nicht initialisiert, sodass verbleibende Bytes Stack-Inhalte enthalten konnten- Ein bösartiger Client konnte pro Dateidownload 1 Byte exfiltrieren; die abgeflossenen Daten konnten Heap-Objektzeiger, Stack-Cookie, lokale Variablen, Zeiger auf globale Variablen und Return-Pointer enthalten
- „Some checksum buffer fixes” stellte sicher, dass das vom Angreifer kontrollierte
s->s2lengthnicht größer als die Übertragungs-Prüfsummenlänge sein kann, und „prevent information leak off the stack” initialisierte den Speicher vonsum2mit 0 - Go initialisiert alle Variablen mit dem zero value und ist daher von dieser Schwachstelle nicht betroffen; außerdem implementiert gokrazy/rsync Protokollversion 27 statt Protokollversion 30, in der die Auswahl anderer Prüfsummen als MD4 eingeführt wurde
-
CVE-2024-12087: Path Traversal über symbolische Links, Schweregrad 7,5
- Laut dem Google Security report kann ein bösartiger Server den Client dazu bringen, beliebige Dateien außerhalb des Zielverzeichnisses zu schreiben, wenn die Synchronisierung symbolischer Links mit
-loder-a(--archive) aktiviert ist - Der Angriff funktioniert im Modus
--inc-recursive, indem mehrere Dateilisten gesendet werden: In der ersten Liste istsymlinkein Verzeichnis, in der nächsten wird derselbe Name in einen symbolischen Link geändert, der auf einen Ort außerhalb des Zielverzeichnisses zeigt - Go selbst verhindert diese Schwachstelle nicht; die Ursache ist ein Logikfehler, bei dem mehrere Dateilisten zusammengeführt, aber anschließend nicht erneut validiert wurden
- Der upstream-Fix ergänzt die fehlende Validierung
- gokrazy/rsync ist nicht betroffen, da es den Modus für inkrementelle Rekursion (
--inc-recursive) nicht implementiert - Inkrementelle Rekursion ermöglicht eine „windowed“-Verarbeitung, ohne die gesamte Dateimenge vor Beginn der Übertragung vollständig zu scannen, bringt aber einen Trade-off zwischen Implementierungskomplexität und Ressourcenverbrauch mit sich
- Laut dem Google Security report kann ein bösartiger Server den Client dazu bringen, beliebige Dateien außerhalb des Zielverzeichnisses zu schreiben, wenn die Synchronisierung symbolischer Links mit
-
CVE-2024-12088: Umgehung von
--safe-links, Schweregrad 7,5- Laut dem Google Security report ist
--safe-linkseine Funktion, die prüft, ob vom Server empfangene symbolische Links auf Ziele innerhalb des Zielverzeichnisses verweisen - Die Umgehung entstand, weil nicht berücksichtigt wurde, ob sich mitten im Zielpfad des symbolischen Links weitere symbolische Links befinden
- Beispielsweise bei
{DESTINATION}/a -> .und{DESTINATION}/foo -> a/a/a/a/a/a/../../zeigtfootatsächlich außerhalb des Zielverzeichnisses, aberunsafe_symlink()nahm an,a/sei ein Verzeichnis, und stufte den Link daher als sicher ein - Der upstream-Fix verschärft
unsafe_symlink(), sodass../außer am Anfang des Pfads nicht mehr erlaubt ist - Go selbst kann eine fehlerhafte Validierungsfunktion nicht verhindern, und gokrazy/rsync ist nicht verwundbar, da es die Funktion
--safe-linksnoch nicht implementiert
- Laut dem Google Security report ist
-
CVE-2024-12086: Offenlegung beliebiger Dateien, Schweregrad 6,8
- Der rsync-Receiver bereinigte im Client-Modus die vom rsync-Sender gelieferten Dateinamen nicht und konnte das Öffnen von Dateien außerhalb des Zielbaums nicht verhindern
- Ein bösartiger Sender konnte den Receiver anweisen, die Prüfsummen beliebiger Dateien außerhalb des Zielbaums zu vergleichen, und durch Beobachtung der Reaktion des Receivers auf 1-Byte-Prüfsummen beliebige Dateien exfiltrieren
- Laut dem Google Security report kann ein Server, wenn sich ein Client mit einem bösartigen Server verbindet, Inhalte beliebiger Dateien vom Rechner des Clients exfiltrieren
- Der upstream-Fix validiert vom Sender gelieferte Pfade und verhindert so das Öffnen von Dateien außerhalb des Zielbaums
- Go bietet APIs, die dies verhindern können; als zugehörige Schutzmaßnahme wird
os.Rootvon Go genannt - gokrazy/rsync ist nicht verwundbar, da es Protokollversion 27 statt Protokollversion 29 implementiert, in der die Fuzzy-Matching-Funktion eingeführt wurde
-
CVE-2024-12747: Race Condition mit symbolischen Links, Schweregrad 5,6
- Laut dem Red Hat Security Advisory handelt es sich um einen Fehler, der durch eine Race Condition in der Verarbeitung symbolischer Links in rsync entsteht
- Standardmäßig überspringt rsync symbolische Links, aber ein Angreifer konnte dieses Standardverhalten umgehen und symbolische Links traversieren, indem er zum passenden Zeitpunkt eine normale Datei in einen symbolischen Link umwandelte
-
Der upstream-Fix änderte den
open()-Aufruf des rsync-Senders so, dass die OptionO_NOFOLLOWverwendet wird- gokrazy/rsync war bis Commit
1b1fbf6verwundbar; dieser Commit führte dieselbeO_NOFOLLOW-Abmilderung wie upstream rsync ein - Damien Neil hielt den gokrazy-Fix für CVE-2024-12747 für unzureichend, da
O_NOFOLLOWnur das Durchlaufen symbolischer Links im letzten Pfadbestandteil verhindert - Zum Beispiel ist bei
os.Open("dir/passwd")weiterhin eine Umgehung möglich, wenn ein früherer Pfadbestandteil wiedirdurch einen symbolischen Link auf/etcersetzt wird - Das Problem wurde im April 2025 an den rsync-Sicherheitskontakt gemeldet und führte zu CVE-2026-29518, das am 2026-05-20 veröffentlicht wurde
- gokrazy/rsync war bis Commit
Schwachstellen im Mai 2026
-
CVE-2026-29518: Race Condition bei symbolischen Links, Schweregrad 7,0
- Laut dem rsync-3.4.3-NEWS-Eintrag handelt es sich um eine TOCTOU-Race-Condition mit symbolischen Links, die im Daemon-Modus ohne chroot eine lokale Rechteausweitung ermöglicht
- Ein rsync-Daemon mit der Einstellung
use chroot = noist einem Time-of-Check/Time-of-Use-Rennen bei übergeordneten Pfadkomponenten ausgesetzt - Ein lokaler Angreifer mit Schreibzugriff auf das Modul kann zwischen der Prüfung des Receivers und
open()eine übergeordnete Verzeichniskomponente durch einen symbolischen Link ersetzen und so beim Lesen eine Offenlegung der Basisdatei bzw. beim Schreiben ein Überschreiben von Dateien außerhalb des Moduls verursachen - Der Standardwert
use chroot = yesist nicht betroffen - Der Upstream-Fix verwendet
secure_relative_open(), ähnlich zu Gosos.Root-API - gokrazy/rsync war verwundbar, bis sowohl der Sender als auch der Receiver auf die traversierungsresistente
os.Root-API umgestellt wurden
-
CVE-2026-43618: Remote-Speicherleck durch Integer-Überlauf, Schweregrad 8,1
- Der Compressed-Token-Decoder des rsync-Receivers akkumuliert einen 32-Bit-Zähler mit Vorzeichen ohne Überlaufprüfung, wodurch ein bösartiger Sender Inhalte aus dem Prozessspeicher offenlegen kann
- Zu den offengelegten Daten können Umgebungsvariablen, Passwörter sowie Heap- und Bibliothekspointer gehören, was ASLR schwächt und weitere Exploits erleichtern kann
- Betroffen sind authentifizierte Daemon-Verbindungen mit aktivierter Komprimierung; ab Protokoll 30 ist diese standardmäßig aktiv, wenn beide Peers Komprimierung ankündigen
- Als Workaround kann die Daemon-Komprimierung in rsyncd.conf mit
refuse options = compressdeaktiviert werden - Der Upstream-Fix ergänzt die fehlende Prüfung
- gokrazy/rsync ist nicht verwundbar, da es keine Komprimierung implementiert; warum Unterstützung für Komprimierung zwar einfach wirkt, aber nicht trivial ist, wird in gokrazy/rsync issue #35 zusammengefasst
-
CVE-2026-43620: Denial of Service nach Out-of-Bounds-Read, Schweregrad 6,5
- Die 2025 zu
send_files()hinzugefügteparent_ndx<0-Schutzabfrage wurde nicht auf den visuell identischen Block inrecv_files()angewendet - Wenn ein bösartiger rsync-Server ein
CF_INC_RECURSE-Kompatibilitäts-Flag und eine fehlerhaft aufgebaute flist sendet, kann der Receiverdir_flist->files[-1]lesen und dereferenzieren, was zu einem deterministischenSIGSEGVführen kann - Betroffen sind alle rsync-Clients, die einen normalen Pull von einer durch Angreifer kontrollierten URL durchführen; wegen
inc_recurse, dem Standard ab Protokoll 30, sind auf Opferseite keine speziellen Optionen nötig - Auf Client-Seite ist
--no-inc-recursiveein Workaround, und der Upstream-Fix fügt dieparent_ndx<0-Schutzabfrage auch inrecv_files()hinzu - gokrazy/rsync implementiert den inkrementell rekursiven Modus
--inc-recursivenicht und ist daher wie bei CVE-2024-12087 nicht betroffen
- Die 2025 zu
-
CVE-2026-43619: Zusätzliche Race Condition bei symbolischen Links, Schweregrad 6,3
- Der Fix für die Race Condition bei symbolischen Links an
open()-Aufrufen des Receivers (CVE-2026-29518) wurde nicht auf andere pfadbasierte Systemaufrufe wiechmod,lchown,utimes,rename,unlink,mkdir,symlink,mknod,link,rmdirundlstatangewendet - Bei einem rsync-Daemon mit
use chroot = nokann ein lokaler Angreifer zwischen der Prüfung des Receivers und dem Systemaufruf eine übergeordnete Verzeichniskomponente durch einen symbolischen Link ersetzen und so auf Ziele außerhalb des exportierten Moduls umleiten - Der Standardwert
use chroot = yesist nicht betroffen - Der Upstream-Fix verarbeitet die betroffenen pfadbasierten Systemaufrufe über ein geöffnetes übergeordnetes
dirfdunter kernelseitig erzwungenen Einschränkungen, etwaopenat2unter Linux 5.6+,O_RESOLVE_BENEATHunter FreeBSD 13+ und macOS 15+ oder komponentenweiser Traversierung mitO_NOFOLLOWin anderen Umgebungen - gokrazy/rsync ist nicht betroffen, da es durchgängig Gos
os.Root-API verwendet
- Der Fix für die Race Condition bei symbolischen Links an
-
CVE-2026-43617: Umgehung hostnamebasierter ACLs, Schweregrad 4,8
- Bei rsync-Daemons mit der globalen rsyncd.conf-Einstellung
daemon chroot = /Xwurde die Reverse-DNS-Auflösung des verbindenden Clients erst durchgeführt, nachdem der Daemon nach/Xgechrootet hatte - Fehlen in
/Xfür die glibc-Auflösung erforderliche Dateien wie/etc/resolv.conf,/etc/nsswitch.conf,/etc/hostsund NSS-Service-Module, schlägt die Auflösung fehl und der Hostname der Verbindung wird auf"UNKNOWN"gesetzt - Hostnamebasierte Deny-Regeln wie
hosts deny = *.evil.examplegreifen dann nicht, sodass ein Angreifer, der PTR-Records kontrolliert, sich mit einem Hostnamen verbinden kann, den der Administrator eigentlich blockieren wollte - IP-basierte ACLs sind nicht betroffen, und die modulbezogene
use chroot-Einstellung steht in keinem Zusammenhang mit dieser Schwachstelle - Der Upstream-Fix verlagert die DNS-Auflösung auf einen früheren Zeitpunkt im Protokoll
- gokrazy/rsync ist nicht verwundbar, da es keine hostnamebasierten Allow-/Deny-Listen implementiert, sondern nur IP-basierte Allow-/Deny-Listen
- Bei rsync-Daemons mit der globalen rsyncd.conf-Einstellung
-
CVE-2026-45232: Out-of-Bounds-Write auf dem Stack, Schweregrad 3,1
- Die Unterstützung des rsync-Clients für HTTP-
CONNECT-Proxys enthält inestablish_proxy_connection()einen Off-by-one-Out-of-Bounds-Write auf dem Stack - Wenn ein Proxy oder ein Man-in-the-Middle-Angreifer in der ersten Antwortzeile 1023 Byte oder mehr ohne
'\n'zurückliefert, kann nachfolgender Code direkt hinter den 1024-Byte-Puffer ein'\0'schreiben und so einen benachbarten Stack-Slot beschädigen - AddressSanitizer meldet einen
stack-buffer-overflowinsocket.c:95im Frame vonestablish_proxy_connection - Der Upstream-Fix validiert die vom Angreifer gelieferten Daten
- gokrazy/rsync ist nicht verwundbar, da es eine solche Proxy-Unterstützung nicht implementiert
- Die Unterstützung des rsync-Clients für HTTP-
Was Go und gokrazy/rsync tatsächlich verhindert haben
- Die Bounds-Checks der Go-Runtime machen aus schwerwiegenderen Sicherheitsproblemen eine Panic; eine Panic bleibt zwar ein Risiko für Denial of Service, wird aber als besserer Fehlermodus bewertet
- Go initialisiert Speicher mit 0 und macht damit Informationslecks wie CVE-2024-12085 unmöglich
- Die
os.Root-API von Go verhindert die meisten der verbleibenden Schwachstellen - Von 12 Schwachstellen wird nur CVE-2026-43617 als Anwendungslogikfehler eingestuft, der sich durch den Einsatz von Go nicht verhindern lässt
- Der zentrale Unterschied zwischen gokrazy/rsync und dem offiziellen Upstream-rsync besteht neben der Implementierung in Go auch darin, dass die Implementierung minimal gehalten ist
- gokrazy/rsync implementiert
--inc-recursive,--safe-links, Komprimierung, Proxy, Hostname-ACLs und andere problematische Funktionen nicht und vermeidet dadurch mehrere Schwachstellen - Wie jede wire-protocol-kompatible rsync-Implementierung zielt gokrazy/rsync auf Protokollversion 27; spätere Protokollversionen führen erhebliche Komplexität ein
- Status von gokrazy/rsync pro CVE zum Zeitpunkt der Veröffentlichung:
2024-12084: Implementierung vorhanden, führte zu einer Panic2024-12085: Funktion aus Protokoll 30, nicht implementiert, daher nicht verwundbar2024-12086: Funktion aus Protokoll 29, nicht implementiert, daher nicht verwundbar2024-12087:inc-recnicht implementiert, daher nicht verwundbar2024-12088:safe-linksnicht implementiert, daher nicht verwundbar2024-12747: Implementierung vorhanden und verwundbar2026-29518: Implementierung vorhanden und gepatcht2026-43617: Host-Deny-Liste nicht implementiert, daher nicht verwundbar2026-43618: Komprimierung nicht implementiert, daher nicht verwundbar2026-43619: Implementierung vorhanden und gepatcht2026-43620:inc-recnicht implementiert, daher nicht verwundbar2026-45232: Proxy nicht implementiert, daher nicht verwundbar
- Alle bekannten Schwachstellen in gokrazy/rsync sind behoben; der obige Status zeigt den Stand zu dem Zeitpunkt, als die jeweiligen CVEs veröffentlicht wurden
- Als die Schwachstellen im Januar 2025 öffentlich wurden, erzeugte gokrazy/rsync bei CVE-2024-12084 eine Panic und war für die TOCTOU-Race-Condition in CVE-2024-12747 anfällig
- Bei der Behebung des TOCTOU-Problems wurde CVE-2026-29518 entdeckt und noch vor der Veröffentlichung dieser CVE in gokrazy/rsync behoben
- CVE-2026-43619 wurde später entdeckt, war in gokrazy/rsync aber bereits durch dieselbe Korrektur behoben, nämlich die durchgängige Nutzung von
os.Root
Rollentrennung und Benennung von Schwachstellen
- In mehreren Schwachstellenberichten wurden die Begriffe „server“ und „client“ verwendet, bei rsync-Übertragungen können jedoch sowohl rsync-Client als auch rsync-Server die Rolle des Senders (sender, Datei-Upload) oder Empfängers (receiver, Datei-Download) übernehmen
- Im Daemon-Modus lässt sich der Dateisystemzugriff auf vorab konfigurierte Modulpfade beschränken, im Command-Mode jedoch nicht
- Die vier Konfigurationen sowie Rollen-, Protokoll- und Schichtenmodell sind im Diagramm rsync combinations zu sehen
- Der ursprüngliche Titel der Arbitrary-File-Leak-Schwachstelle (CVE-2024-12086) „Server leaks arbitrary client files“ ist leicht missverständlich
- Präziser ist die Formulierung, dass ein rsync-Empfänger beliebige Dateien an einen bösartigen Sender preisgibt
- Ein bösartiger Client-Sender kann in Umgebungen wie dem Command-Mode über SSH einen ungepatchten entfernten rsync dazu bringen, Dateien außerhalb des Zielbaums zu öffnen, etwa die System-Passwortdatenbank
/etc/shadow - Im Daemon-Modus verhindert der Server diesen Angriff durch zusätzliche Pfadnormalisierung (Path Sanitization)
- Auch die Symlink-Path-Traversal-Schwachstelle (CVE-2024-12087) wird als „malicious server“ beschrieben, gemeint ist aber genauer ein bösartiger Sender, der entweder Client oder Server sein kann
Vergleich mit OpenBSD openrsync
- Das OpenBSD-Projekt ist für seinen Sicherheitsfokus bekannt; openrsync validiert die Checksum-Länge und unterstützt bei Checksum-Größe/-Algorithmus nur MD4, sodass es nicht von Heap Buffer Overflow (CVE-2024-12084) und Stack Info Leak (CVE-2024-12085) betroffen ist
- Wie gokrazy/rsync ist openrsync nicht von CVE-2024-12086, CVE-2024-12087 und CVE-2024-12088 betroffen, weil die entsprechenden Funktionen nicht implementiert sind
- Selbst wenn eine Verwundbarkeit bestanden hätte, hätte Defense in Depth durch OpenBSD
unveil(2)undpledge(2)beim Ausführen auf OpenBSD einen erfolgreichen Exploit möglicherweise verhindert, indem der Dateisystemzugriff eingeschränkt wird - openrsync war nicht von CVE-2024-12747 betroffen, weil es ab dem Zeitpunkt der Implementierung der Symlink-Unterstützung
O_NOFOLLOWverwendete O_NOFOLLOWist für dieses Problem jedoch keine ausreichende Korrektur, daher ist openrsync von CVE-2026-29518 betroffen- Das Paket von Mai 2026 ist insofern ähnlich, als die meisten betreffenden Funktionen ebenfalls nicht implementiert waren
- openrsync ist von den meisten gemeldeten Schwachstellen nicht betroffen, weil es Validierung sorgfältig implementiert, die Angriffsfläche begrenzt und Defense in Depth anwendet
Defense in Depth und os.Root
-
Linux-Mount-Namespace
- Wenige Wochen nach dem Start des Projekts gokrazy/rsync wurde eine Funktion hinzugefügt, die auf Linux das Absenken von Privilegien sowie die Nutzung von Mount-/PID-Namespaces unterstützt, um den Zugriff auf Dateisystemobjekte einzuschränken
- Dieser Ansatz funktioniert gut zur Abschwächung von Path-Traversal-Angriffen, benötigt aber Privilegien; er muss daher entweder als
rootlaufen oder innerhalb eines Linux-User-Namespace, wenn dieser auf der Distribution bzw. dem System aktiviert ist - Der Mount-Namespace eignet sich für Server-Konfigurationen, ist aber für interaktive einmalige Übertragungen, die typischerweise unter dem Konto eines normalen Benutzers laufen, oft nicht nutzbar
-
systemd-Härtung
- Derselbe Commit, der die Unterstützung für Linux-Mount-/PID-Namespaces eingeführt hat, enthielt auch eine systemd-Service-Datei, die den Dateisystemzugriff auf das Home-Verzeichnis beschränkt; im README wird je nach Anwendungsfall empfohlen, den Dateisystemzugriff noch weiter einzuschränken
- Wenn diese Dateisystemeinschränkungen korrekt konfiguriert sind, mindern sie die Schwachstellen File Leak (CVE-2024-12086) und Path Traversal (CVE-2024-12087)
- Die Symlink Race Condition (CVE-2024-12747) hängt von einer Privilegienausweitung über den rsync-Prozess ab, aber dank der Funktion DynamicUser hat der Prozess weniger Rechte als andere Benutzer
- Wie der Mount-Namespace ist das gut für Server-Konfigurationen, aber umständlich für die Einrichtung bei interaktiver Einmalnutzung
-
Linux Landlock
- Durch Porting OpenBSD pledge() to Linux (2022) wurde daran erinnert, dass es unter Linux mit der Landlock API ebenfalls eine nicht privilegierte, prozessbezogene Zugriffskontrolle gibt, ähnlich zu OpenBSDs
unveil(2) - Die Grundidee ist: Sobald das Programm die Verzeichnisse kennt, mit denen es arbeiten wird, kann es mit einem Aufruf wie
unveil("/home/michael/backups", "rw");den Zugriff auf Dateisystemorte außerhalb dieses Pfads dauerhaft verhindern - Im März 2025 wurde Landlock-Unterstützung implementiert, um den Dateisystemzugriff einzuschränken
- Nach passender Konfiguration lassen sich selbst bei nicht privilegierten
gokrazy/rsync-Ausführungen rsync-Übertragungen auf schreibgeschützten Zugriff auf die Quelle und Lese-/Schreibzugriff auf das Zielverzeichnis beschränken - Ein Nachteil ist, dass Landlock auf Prozessebene arbeitet
- In einer Landlock-Policy müssen auch die vom Programm benötigten Dateien enthalten sein;
gokrazy/rsyncmuss zum Beispiel/etc/passwdlesen können, um Benutzer-IDs nachzuschlagen. Wenn ein Angreifer also auf/etc/passwdzielt, hilft Landlock nicht
- Durch Porting OpenBSD pledge() to Linux (2022) wurde daran erinnert, dass es unter Linux mit der Landlock API ebenfalls eine nicht privilegierte, prozessbezogene Zugriffskontrolle gibt, ähnlich zu OpenBSDs
-
os.Rootin Go- Im Februar 2025 führte Go 1.24 die gegen Path Traversal resistente
os.Root-API ein; der Hintergrund dazu ist in Damien Neils The Go Blog: Traversal-resistant file APIs zusammengefasst - Im Vergleich zu Landlock bietet
os.Rooteine feinere Kontrolle pro Dateisystemoperation - Mit Go 1.25, das im August 2025 erschien, kamen weitere Methoden zu
os.Roothinzu, wodurch es für die meisten Dateisystemanwendungen zu einer praktischen Option wurde - Die gesamte Dateisystemnutzung von
gokrazy/rsyncwurde aufos.Rootumgestellt; das passt gut zu dem Modell, dass der Benutzer Ein-/Ausgabeverzeichnisse konfiguriert, über das Netzwerk empfangene Dateinamen aber nicht vertrauenswürdig sind - Auch Systemaufrufe, die sich scheinbar nicht direkt über die API erstellen lassen, wie
mknod(2), können sicher verwendet werden - Damien Neil erklärt, dass man mit
os.Root.OpenFiledas übergeordnete Verzeichnis des Ziels öffnet, mitFile.Fdden Dateideskriptor dieses Verzeichnisses erhält und dann mitgolang.org/x/sys/unix#Mknodatdie Datei erstellt - Ein reales Nutzungsbeispiel findet sich in
internal/receiver/generatormknod_linux.go, Zeile 15-29 - Linux kennt
mknodat(2), aber nach Stand von Linux 7.0 keinbindatals Gegenstück zubind(2) - Lennart Poettering schlug vor, dass man ohne
bindatmit einem Trick an/proc/self/<fd>/foobarbinden kann, der die Pfadauflösung umgeht - Gibt man hinter dem bekanntermaßen sicheren
/proc/self/<fd>nicht einen Pfad, sondern nur den Basename, also die letzte Pfadkomponente, an, wird die Pfadauflösung umgangen; der zugehörige Code steht in Zeile 49-56 - Mit diesen beiden Tipps nutzt
gokrazy/rsyncab v0.3.1os.Rootvollständig, und jeder Dateisystemzugriff ist Path-Traversal-sicher
- Im Februar 2025 führte Go 1.24 die gegen Path Traversal resistente
Wichtige Lehren
- Alle Schwachstellen außer den TOCTOU-Schwachstellen (CVE-2024-12747, CVE-2026-29518, CVE-2026-43619) gingen auf fehlende oder fehlerhafte Eingabevalidierung zurück
- In drei Fällen gab es von vornherein überhaupt keine Validierung, und bei CVE-2024-12088 ist die Pfadauflösung im Dateisystem so schwierig, dass die bestehende Validierung nicht alle Randfälle abdeckte
- Die wertvollsten strukturellen Korrekturen sind Validierungen, die immer aktiv sind, wie Grenzprüfungen, sowie standardmäßig sichere APIs wie
os.Rootin Go - Einige Schwachstellen entstanden durch die Weiterentwicklung des rsync-Protokolls: Neue Funktionen wurden zu Code hinzugefügt, der ursprünglich ausreichend validierte, ohne dass die Validierung korrekt an die neuen Funktionen angepasst wurde
- Die Aushandlung des Checksum-Algorithmus und die inkrementelle Rekursion wurden mit Protokollversion 30 hinzugefügt, und die bestehende Validierung wurde nicht an die Verarbeitung der neuen Funktionen angepasst
gokrazy/rsyncund openrsync waren gegen 8 von 12 Sicherheitslücken nicht anfällig, einfach weil sie die verwundbaren Funktionen nicht implementierten- Diese Funktionen wurden irgendwann in rsync eingebaut, weil sie für jemanden wertvoll waren; das bedeutet nicht, dass man die Softwareentwicklung einstellen sollte
- Die ideale Wahl ist eine Implementierung, deren Komplexität zum Anwendungsfall passt und ihm angemessen ist: für einfache Anwendungsfälle eine einfache Implementierung und nur bei Bedarf eine voll ausgestattete Implementierung
1 Kommentare
Lobste.rs-Kommentare
os.Rootin ihre Standardbibliothek aufnehmen sollteNachdem wir bei SecureDrop einige Path-Traversal-Schwachstellen erlebt hatten, haben wir eine stark vereinfachte Version verwendet, und wenn man jetzt die richtige API nutzt, verschwindet gleich eine ganze Klasse von Schwachstellen
os.Rootals Go zu sein