Der Autor der Standard-C-Bibliothek Cosmopolitan und der Plattform Redbean hat die Implementierung des Isolationsmechanismus pledge() für Linux bekannt gegeben. Ursprünglich wurde pledge vom OpenBSD-Projekt entwickelt und ermöglicht es, Anwendungen selektiv den Zugriff auf nicht benötigte Systemaufrufe zu verweigern (es wird eine Art Whitelist für Systemaufrufe erstellt, während andere Aufrufe blockiert werden). Im Gegensatz zu den in Linux verfügbaren Mechanismen zur Beschränkung des Zugriffs auf Systemaufrufe, wie seccomp, wurde der pledge-Mechanismus von Anfang an mit dem Ziel entwickelt, die Anwendung zu vereinfachen.
Die fehlgeschlagene Initiative zur Isolierung von Anwendungen in der Basisumgebung von OpenBSD unter Verwendung des Systrace-Mechanismus hat gezeigt, dass die Isolierung auf der Ebene einzelner Systemaufrufe zu komplex und zeitaufwendig ist. Als Alternative wurde pledge vorgeschlagen, mit dem Regeln zur Isolierung erstellt werden können, ohne sich in Details vertiefen und mit vordefinierten Zugriffsklassen manipulieren zu müssen. Beispielsweise werden die Klassen stdio (Ein-/Ausgabe), rpath (nur Lesezugriff auf Dateien), wpath (Schreibzugriff auf Dateien), cpath (Dateierstellung), tmppath (Umgang mit temporären Dateien), inet (Netzwerksockets), unix (Unix-Sockets), dns (DNS-Resolution), getpw (Lesezugriff auf die Benutzerdatenbank), ioctl (ioctl-Aufruf), proc (Prozessverwaltung), exec (Prozessstart) und id (Zugriffsrechteverwaltung) angeboten.
Die Regeln für den Umgang mit Systemaufrufen werden in Form von Annotationen festgelegt, die eine Liste der erlaubten Klassen von Systemaufrufen und ein Array von Dateipfaden enthalten, zu denen der Zugriff erlaubt ist. Nach der Erstellung und dem Start der modifizierten Anwendung übernimmt der Kernel die Kontrolle über die Einhaltung der festgelegten Regeln.
Die Implementierung von pledge für FreeBSD entwickelt sich unabhängig weiter. Diese ermöglicht die Isolierung von Anwendungen, ohne deren Code zu ändern, während der Aufruf von pledge in OpenBSD eine enge Integration mit der Basisumgebung anstrebt und Anmerkungen im Code jeder Anwendung hinzufügt.
Die Entwickler des pledge-Ports für Linux haben sich ein Beispiel an FreeBSD genommen und statt Änderungen am Code die Overlay-Utility pledge.com erstellt. Diese ermöglicht die Anwendung von Einschränkungen, ohne den Anwendungs-Code zu verändern. Zum Beispiel genügt es, um die curl-Utility mit Zugang nur zu den Klassen der Systemaufrufe stdio, rpath, inet und threadstdio auszuführen, „./pledge.com -p 'stdio rpath inet thread' curl http://example.com“ einzugeben.
Die Utility pledge funktioniert in allen Linux-Distributionen, beginnend mit RHEL6, und benötigt keinen Root-Zugriff. Zusätzlich wird auf Basis der Bibliothek cosmopolitan eine API bereitgestellt, um Einschränkungen im C-Code zu verwalten, die unter anderem die Erstellung von Enklaven ermöglichen, um den Zugang zu bestimmten Funktionen der Anwendung selektiv einzuschränken.
Die Implementierung erfordert keine Änderungen am Kernel — die Pledge-Einschränkungen werden in die SECCOMP BPF-Regeln überführt und mit dem nativen Linux-Mechanismus zur Isolation von Systemaufrufen verarbeitet. Zum Beispiel wird der Aufruf pledge("stdio rpath", 0) in den 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
