Vorschlag für eine Linux-Kernelmodifikation zur Erhöhung der Sicherheit (vorbeugend gegen Fehler bei der Rechtevergabe von Verzeichnissen)

Dynamische umask für die zugriffsbezogenen Rechte an verlinkten Objekten in Unix-Dateisystemen

Version 1.0, 28.08.2005, Hauke Laging, hauke@laging.de

das Problem

Wenn Anwendungen ihre Dateien in Verzeichnissen ablegen, die für andere Benutzer beschreibbar sind, werden Symlinkangriffe möglich: Die vorhandene Datei wird gelöscht und duch einen Symlink ersetzt. Ein Missbrauch der fraglichen Anwendung ist möglich, wenn diese die verlinkte Datei lesen oder schreiben kann, der angreifende Prozess aber nicht. Diese Angriffe sind in erster Linie destruktiver Natur (denial of service). Um geschütze Daten lesen zu kännen, müsste die missbrauchte Anwendung sie irgendwie dem angreifenden Prozess zugänglich machen, etwa über die Ausgabe in eine Datei; ein eher seltenes Problem. Es können aber so vitale Systemdateien überschrieben werden, wenn es sich um einen Prozess mit root-Rechten handelt.

Natürlich lässt sich dieses Problem leicht durch eine korrekte Vergabe der Verzeichnisrechte lösen, aber das ist kein Argument, da man im Prinzip jede Sicherheitslücke hätte vermeiden können. Es geht im folgenden um einen zentralen Ansatz, der ein Problem, das immer wieder auftreten wird, eindämmt.

Lösung

Der Kernel sollte um eine (abschaltbare) Funktion erweitert werden, die dieses Problem (teilweise) löst. Die Rechte eines Symlinks werden nicht beachtet, aber sein Ersteller wird gespeichert. Der Kernel müsste bei der Prüfung lediglich zusätzlich prüfen,

  1. ob das Objekt, auf das zugegriffen wird, ein Symlink ist

  2. ob der Ersteller des Symlinks über die Zugriffsrechte verfügt, die der fragliche Prozess gerade für sich beansprucht.

Wenn sich herausstellt, dass eine kritische Situation vorliegt, der Prozess also gerade Rechte ausüben will, die der Symlinkersteller nicht hat, würden dem Prozess diese Rechte verweigert. Es würde quasi aus den Rechten des Symlinkerstellers eine (invertierte) umask gemacht, die auf die Zugriffsprüfung des Prozesses angewendet wird.

Aufwand

Der Realisierungsaufwand wäre gering, im wesentlichen würde der bestehende Prüfcode zweimal aufgerufen. Der aufwändigste Teil dürfte die Deaktivierungsmöglichkeit über /proc sein.

Probleme

Hardlinks

Dieser Ansatz funktioniert nicht, wenn Hardlinks angelegt werden, allerdings funktionieren diese nur auf demselben Volume. Das Problem würde damit faktisch auf /tmp und /var beschränkt.

Änderungen am Systemverhalten gefährden die Kompatibilität

Das ist prinzipiell natürlich richtig, allerdings konnte mir auch auf mehrfache Nachfrage von den Leuten, die dieses Problem anführen, kein praktisches Beispiel genannt werden. Es ergibt auch augenscheinlich keinen Sinn, einen Link anzulegen, den man selber gar nicht benutzen kann, damit ein anderer Benutzer ihn nutzt. Genauso unsinnig erscheint es, dass Programme solche Links nutzen wollen sollten.

Da dies ein Selbstschutzmechanismus ist, könnte diese Funktion auch immer durch ein Wrapperscript (über das Setzen des entsprechenden Wertes in /proc) für den jeweiligen Prozess deaktiviert werden.

Es wäre möglich, den Kernel eine über /proc abrufbare Statistik darüber führen zu lassen, wann welche PID (und vielleicht PPID zur besseren Nachverfolgung bei kurzlebigen Prozessen) welches Users versuchte einen Link anzulegen, was vom Kernel in der beschriebenen Weise unterbunden wurde. Dass dieser Zähler konstant bei Null bleibt, könnte den einen oder anderen Kritiker beruhigen.

Code und Konfigurationsdateien

Dies wäre kein Schutz gegen den Versuch, einer Anwendung Code oder Konfigurationsdateien unter Ausnutzung der fraglichen "Sicherheitslücke" unterzujubeln, da ein Angreifer diese Dateien natürlich lesen, schreiben und ausführen könnte. Allerdings fiele dies nicht in die Kategorie Symlinkangriff, da der Angreifer anstelle eines Symlinks auch gleich Dateien anlegen könnte.

Alternativen

das Anlegen von Links kontrollieren

Eine Alternative wäre, Prozessen das Anlegen von Links zu verbieten, wenn sie keine Rechte bezüglich des Ziels haben. Abgesehen davon, dass dies ein weitaus schwerwiegenderer Eingriff in das System wäre, löste das das Problem nicht, da es legitim ist, Links auf Dateien anzulegen, die man selber nur lesen kann. Praktikabel wäre das also nur bei Linkzielen, die völlig unerreichbar sind, was aber das Problem dann nicht messbar reduzierte.

Sinnvoll wäre dieser Ansatz bei Hardlinks. Die sind dafür weniger üblich - KDE etwa bietet dem Anwender nur das Anlegen von Symlinks an - und daher insgesamt weniger kritisch. Auch hier kann man einwenden, das nichts dagegen spricht, etwas zu verlinken, was man immerhin lesen darf. Die sinnvolle Einschränkung wäre hier, das Anlegen von Hardlinks in Verzeichnissen zu verbieten, die einem nicht gehören. Ein Verlust wäre das nicht. Eine Ausnahme könnte für Dateien gemacht werden, die der den Hardlink anlegende Nutzer sowohl lesen als auch schreiben kann.

Da hiermit die bösen Programme gestoppt werden sollen, wäre es nicht praktikabel, diese Funktion (wie oben für den Fall des Aufrufens von Links skizziert) abschaltbar zu machen. Dies wäre, wenn man sich denn den Aufwand machen will, allenfalls in der Weise denkbar, dass root-Prozesse die der User mit diesem Recht ausstatten könnten, was erst einmal wenig praktikabel erscheint, da es keinen einheitlichen ("kompatiblen") Weg gibt, das Starten von Programmen abzufangen. Praktikabel wäre wohl nur, analog zu hotplug eine Art Exception-Handler zu schreiben, der aktiviert wird, wenn der Kernel ein solches Anliegen stoppt. Dieser Prozess könnte dann anhand seiner Konfiguration entscheiden, ob der fragliche Prozess dauerhaft das Recht erhält, solche komischen Hardlinks anzulegen, ob es ihm (und sich weitere Aufrufe des Exception-Handlers zu sparen) dauerhaft verweigert wird oder - o wei - ob man alle Aufrufe einzeln prüfen will. Prinzipiell könnte ja jemand dieses Recht nur für bestimmte Verzeichnisse konfigurieren wollen...