1 Punkte von GN⁺ 2 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • 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-Puffer char sum2[SUM_LENGTH]
    • MAX_DIGEST_LEN kann größer werden, wenn Unterstützung für SHA256- oder SHA512-Prüfsummen einkompiliert ist, sodass ein Angreifer die Grenze des Puffers sum2 um bis zu 48 Byte überschreiben konnte
    • Das Problem wurde im September 2022 mit Commit ae16850 eingeführt, der Unterstützung für SHA256/SHA512-Prüfsummen hinzufügte
    • Der upstream-Fix ersetzte sum2 durch das dynamisch allokierte sum2_array und korrigierte Allokation und Prüfung anhand der Prüfsummenlänge des Übertragungsalgorithmus xfer_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 ChecksumLength auf 512, erzeugt die Go-Laufzeit panic: 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
  • 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-Puffer char sum2[MAX_DIGEST_LEN] und verglich ihn mit memcmp(), aber der lokale Stack-Puffer sum2 wurde 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->s2length nicht größer als die Übertragungs-Prüfsummenlänge sein kann, und „prevent information leak off the stack” initialisierte den Speicher von sum2 mit 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 -l oder -a(--archive) aktiviert ist
    • Der Angriff funktioniert im Modus --inc-recursive, indem mehrere Dateilisten gesendet werden: In der ersten Liste ist symlink ein 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
  • CVE-2024-12088: Umgehung von --safe-links, Schweregrad 7,5

    • Laut dem Google Security report ist --safe-links eine 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/../../ zeigt foo tatsächlich außerhalb des Zielverzeichnisses, aber unsafe_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-links noch nicht implementiert
  • 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.Root von 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 Option O_NOFOLLOW verwendet wird

    • gokrazy/rsync war bis Commit 1b1fbf6 verwundbar; dieser Commit führte dieselbe O_NOFOLLOW-Abmilderung wie upstream rsync ein
    • Damien Neil hielt den gokrazy-Fix für CVE-2024-12747 für unzureichend, da O_NOFOLLOW nur 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 wie dir durch einen symbolischen Link auf /etc ersetzt 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

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 = no ist 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 = yes ist nicht betroffen
    • Der Upstream-Fix verwendet secure_relative_open(), ähnlich zu Gos os.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 = compress deaktiviert 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ügte parent_ndx<0-Schutzabfrage wurde nicht auf den visuell identischen Block in recv_files() angewendet
    • Wenn ein bösartiger rsync-Server ein CF_INC_RECURSE-Kompatibilitäts-Flag und eine fehlerhaft aufgebaute flist sendet, kann der Receiver dir_flist->files[-1] lesen und dereferenzieren, was zu einem deterministischen SIGSEGV fü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-recursive ein Workaround, und der Upstream-Fix fügt die parent_ndx<0-Schutzabfrage auch in recv_files() hinzu
    • gokrazy/rsync implementiert den inkrementell rekursiven Modus --inc-recursive nicht und ist daher wie bei CVE-2024-12087 nicht betroffen
  • 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 wie chmod, lchown, utimes, rename, unlink, mkdir, symlink, mknod, link, rmdir und lstat angewendet
    • Bei einem rsync-Daemon mit use chroot = no kann 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 = yes ist nicht betroffen
    • Der Upstream-Fix verarbeitet die betroffenen pfadbasierten Systemaufrufe über ein geöffnetes übergeordnetes dirfd unter kernelseitig erzwungenen Einschränkungen, etwa openat2 unter Linux 5.6+, O_RESOLVE_BENEATH unter FreeBSD 13+ und macOS 15+ oder komponentenweiser Traversierung mit O_NOFOLLOW in anderen Umgebungen
    • gokrazy/rsync ist nicht betroffen, da es durchgängig Gos os.Root-API verwendet
  • CVE-2026-43617: Umgehung hostnamebasierter ACLs, Schweregrad 4,8

    • Bei rsync-Daemons mit der globalen rsyncd.conf-Einstellung daemon chroot = /X wurde die Reverse-DNS-Auflösung des verbindenden Clients erst durchgeführt, nachdem der Daemon nach /X gechrootet hatte
    • Fehlen in /X für die glibc-Auflösung erforderliche Dateien wie /etc/resolv.conf, /etc/nsswitch.conf, /etc/hosts und 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.example greifen 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
  • 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 in establish_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-overflow in socket.c:95 im Frame von establish_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

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 Panic
    • 2024-12085: Funktion aus Protokoll 30, nicht implementiert, daher nicht verwundbar
    • 2024-12086: Funktion aus Protokoll 29, nicht implementiert, daher nicht verwundbar
    • 2024-12087: inc-rec nicht implementiert, daher nicht verwundbar
    • 2024-12088: safe-links nicht implementiert, daher nicht verwundbar
    • 2024-12747: Implementierung vorhanden und verwundbar
    • 2026-29518: Implementierung vorhanden und gepatcht
    • 2026-43617: Host-Deny-Liste nicht implementiert, daher nicht verwundbar
    • 2026-43618: Komprimierung nicht implementiert, daher nicht verwundbar
    • 2026-43619: Implementierung vorhanden und gepatcht
    • 2026-43620: inc-rec nicht implementiert, daher nicht verwundbar
    • 2026-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) und pledge(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_NOFOLLOW verwendete
  • O_NOFOLLOW ist 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 root laufen 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/rsync muss zum Beispiel /etc/passwd lesen können, um Benutzer-IDs nachzuschlagen. Wenn ein Angreifer also auf /etc/passwd zielt, hilft Landlock nicht
  • os.Root in 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.Root eine feinere Kontrolle pro Dateisystemoperation
    • Mit Go 1.25, das im August 2025 erschien, kamen weitere Methoden zu os.Root hinzu, wodurch es für die meisten Dateisystemanwendungen zu einer praktischen Option wurde
    • Die gesamte Dateisystemnutzung von gokrazy/rsync wurde auf os.Root umgestellt; 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.OpenFile das übergeordnete Verzeichnis des Ziels öffnet, mit File.Fd den Dateideskriptor dieses Verzeichnisses erhält und dann mit golang.org/x/sys/unix#Mknodat die 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 kein bindat als Gegenstück zu bind(2)
    • Lennart Poettering schlug vor, dass man ohne bindat mit einem Trick an /proc/self/<fd>/foobar binden 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/rsync ab v0.3.1 os.Root vollständig, und jeder Dateisystemzugriff ist Path-Traversal-sicher

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.Root in 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/rsync und 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

 
GN⁺ 2 시간 전
Lobste.rs-Kommentare
  • Großartiger Artikel. So gut, dass jede Sprache eine API wie os.Root in ihre Standardbibliothek aufnehmen sollte
    Nachdem 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
    • Stimmt. Der eigentliche Protagonist dieses Blogposts scheint eher os.Root als Go zu sein