Theo de Raadt schlug vor, einen neuen Mechanismus zur Verringerung der Angriffsfläche in OpenBSD einzuführen, der über die Erweiterung der Möglichkeiten des Systemaufrufs openat implementiert wird. Patches mit der Implementierung zusätzlicher Flags für openat und open, die den Zugang zu oberen Verzeichnissen durch "\/.." und den Zugriff über absolute Pfade einschränken, wurden für den Kernel, libc und einige Anwendungen aus dem Basissystem vorbereitet. Die Änderungen sind bisher nicht in OpenBSD-current integriert und befinden sich in der Diskussion unter den Entwicklern.
Die Gruppe der Systemaufrufe openat(2) funktioniert wie ein Analogon zu open(2), mit dem Unterschied, dass wenn im Parameter "path" ein relativer Pfad angegeben wird, die zu öffnende Datei relativ zum Verzeichnis, das mit dem Dateideskriptor "fd" verbunden ist, und nicht relativ zum aktuellen Arbeitsverzeichnis bestimmt wird. Wenn ein absoluter Pfad an openat übergeben wird, beispielsweise: int dirfd = open("\/tmp", O_RDONLY | O_DIRECTORY); int hfd = openat(dirfd, "\/etc\/hosts", O_RDONLY);
Die Funktion openat() ignoriert "dirfd" und consequently wird der absolute Pfad auf herkömmliche Weise verarbeitet.
Daher stärkt der Austausch von open() durch openat() an sich nicht die Sicherheit des Programms. Ein solcher Aufruf kann die Pfadauflösung beschleunigen, schränkt jedoch nicht den Zugriff auf das Dateisystem ein. Auch die Flags, die absolute Pfade verbieten (z. B. RESOLVE_BENEATH und/oder RESOLVE_IN_ROOT für openat2 in Linux), bieten keinen Schutz: Der Programmierer muss sie zu allen geeigneten Aufrufen hinzufügen, und wenn ein Angreifer die Kontrolle über den Prozess übernimmt, kann er andere Wege nutzen, um Dateien zu öffnen.
Im Zuge der Arbeit an dem Tool openrsync hatte Theo die Notwendigkeit, die Fähigkeit, das Dateisystem zu durchqueren, einzuschränken, aber dies war mit den Funktionen unveil() und pledge() nicht möglich. Daher entstand die Idee für einen Mechanismus, der openat() ähnlich ist, jedoch Sicherheitseigenschaften bietet, die pledge/unveil ergänzen oder sogar ohne deren Vorhandensein funktionieren.
Die Hauptidee besteht darin, Einschränkungen zu einem Teil des Verzeichnisses des Deskriptors zu machen. Daher wird das Flag F_BELOW vorgeschlagen, das über fcntl() gesetzt werden kann, oder das Flag O_BELOW für open(). Ein so eingeschränkter Deskriptor "dirfd" erlaubt nur den Zugriff nach unten im Verzeichnisbaum: Aufrufe von openat() mit absolutem Pfad oder mit Übergängen nach oben über ".." werden mit dem Fehler ENOENT beendet. Im Falle eines Angriffs, der zur Ausführung von Code führt, wird die Tabelle der Dateideskriptoren des Prozesses weniger funktionale "dirfd" enthalten, was die Angriffsfläche einschränkt.
Quelle: opennet.ru
