Der Autor der Standard-C-Bibliothek Cosmopolitan und der Plattform Redbean hat die Umsetzung des Pledge()-Isolationsmechanismus für Linux bekannt gegeben. Ursprünglich wurde Pledge vom OpenBSD-Projekt entwickelt und ermöglicht es, Anwendungen selektiv den Zugriff auf ungenutzte Systemaufrufe zu untersagen (für jede Anwendung wird eine Art von Whitelist der Systemaufrufe erstellt, während andere Aufrufe verboten werden). Im Gegensatz zu den in Linux verfügbaren Mechanismen zur Zugangskontrolle für Systemaufrufe, wie seccomp, wurde der Pledge-Mechanismus von Anfang an mit dem Ziel entwickelt, die Anwendung zu vereinfachen.
Die gescheiterte Initiative zur Isolierung von Anwendungen des Basisumfelds von OpenBSD unter Verwendung des Systrace-Mechanismus hat gezeigt, dass die Isolierung auf der Ebene einzelner Systemaufrufe zu kompliziert und aufwendig ist. Als Alternative wurde Pledge vorgeschlagen, das es ermöglicht, Isolationsregeln zu erstellen, ohne sich in die Details zu vertiefen und bereits bestehende Zugriffsklassen zu nutzen. Zum Beispiel werden Klassen wie stdio (Eingabe/Ausgabe), rpath (nur Lesezugriff auf Dateien), wpath (Schreibzugriff auf Dateien), cpath (Dateierstellung), tmppath (Arbeiten mit temporären Dateien), inet (Netzwerksockets), unix (Unix-Sockets), dns (DNS-Resolution), getpw (Lesezugriff auf die Benutzerdatenbank), ioctl (ioctl-Aufruf), proc (Prozessverwaltung), exec (Prozessausführung) und id (Zugriffsrechteverwaltung) angeboten.
Die Regeln für den Umgang mit Systemaufrufen werden in Form von Anmerkungen festgelegt, die eine Liste der erlaubten Klassen von Systemaufrufen sowie ein Array von Dateipfaden enthalten, auf die der Zugriff erlaubt ist. Nach dem Erstellen und Starten der modifizierten Anwendung übernimmt der Kernel die Überwachung der Einhaltung der festgelegten Regeln.
Eine separate Implementierung von Pledge für FreeBSD wird entwickelt, die die Isolierung von Anwendungen ermöglicht, ohne deren Code zu ändern, während der Aufruf von Pledge in OpenBSD auf eine enge Integration mit dem Basisumfeld und das Hinzufügen von Anmerkungen im Code jeder Anwendung abzielt.
Die Entwickler des Pledge-Ports für Linux haben sich am Beispiel von FreeBSD orientiert und anstelle von Änderungen am Code ein übergreifendes Tool pledge.com erstellt, das es ermöglicht, Einschränkungen anzuwenden, ohne den Anwendungscode zu ändern. Um beispielsweise das Tool curl mit eingeschränktem Zugriff nur auf die Klassen der Systemaufrufe stdio, rpath, inet und threadstdio zu starten, genügt der Befehl „./pledge.com -p 'stdio rpath inet thread' curl http://example.com”.
Das Tool pledge funktioniert in allen Linux-Distributionen ab RHEL6 und benötigt keinen Root-Zugriff. Darüber hinaus wird auf Basis der Bibliothek cosmopolitan eine API bereitgestellt, die eine Verwaltung der Einschränkungen im C-Code ermöglicht und es unter anderem erlaubt, Enklaven zur selektiven Einschränkung des Zugriffs in Verbindung mit bestimmten Funktionen der Anwendung zu erstellen.
Die Implementierung erfordert keine Änderungen am Kernel — die pledge-Einschränkungen werden in SECCOMP BPF-Regeln übersetzt und mit dem nativen Isolationsmechanismus für Systemaufrufe in Linux verarbeitet. Beispielsweise wird der Aufruf pledge("stdio rpath", 0) in einen BPF-Filter umgewandelt: static const struct sock_filter kFilter[] = { /* L0 */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, syscall, 0, 14 - 1), /* L1 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])), /* L2 */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 2, 4 - 3, 0), /* L3 */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 10, 0, 13 - 4), /* L4 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[1])), /* L5 */ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, ~0x80800), /* L6 */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 8 - 7, 0), /* L7 */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 2, 0, 13 - 8), /* L8 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[2])), /* L9 */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 12 - 10, 0), /*L10*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 6, 12 - 11, 0), /*L11*/ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 17, 0, 13 - 11), /*L12*/ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /*L13*/ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)), /*L14*/ /* next filter */ };
Quelle: opennet.ru
