Überblick über Hubris IPC
- Hubris verwendet einen kleinen, nicht anwendungsabhängigen Kernel, während sich der Großteil des Codes (Treiber, Anwendungslogik, Netzwerk-Stack usw.) in separat kompilierten, isolierten Tasks befindet
- Diese Tasks können über ein Cross-Task-Messaging-System (IPC) miteinander kommunizieren
- Das IPC von Hubris besteht aus drei Kernoperationen, die im Kernel implementiert sind: RECV, SEND, REPLY
- RECV: Nimmt die eingehende Nachricht mit der höchsten Priorität entgegen oder blockiert, bis eine Nachricht eintrifft
- SEND: Überträgt Nachricht und Kontrolle an den empfangenden Task und hält den Aufrufer an. Der Aufrufer wechselt in einen Wartezustand, bis er eine Antwort erhält
- REPLY: Liefert eine Antwort an einen Task, der zuvor SEND verwendet hat, damit er seine Ausführung fortsetzen kann
Neue und interessante Fehlermodi
- Da IPC Task-Grenzen überschreitet und die Tasks in Hubris separat kompilierte Programme sind, muss man vorsichtig sein, wenn man bei IPC dieselben Annahmen trifft, die der Compiler bei Funktionsaufrufen voraussetzt
- Alle Tasks, die in Hubris als IPC-Server fungieren, müssen potenzielle Fehler wie die folgenden behandeln:
- Empfang einer Nachricht mit einer ungeeigneten Operation Code für die Schnittstelle
- Empfang eines nicht interpretierbaren Byte-Bündels statt des erwarteten Nachrichtentyps oder einer zu kurzen bzw. zu langen Nachricht
- Empfang nicht des benötigten Speichers (z. B. beschreibbarer Speicher)
In normalen und korrekten Programmen tritt das nicht auf
- In normalen Hubris-Programmen treten die oben genannten Situationen nicht auf
- Tasks sind durch die Konfiguration des Build-Systems miteinander verbunden, sodass sie kaum miteinander verwechselt werden können
- Client und Server verwenden generierten Rust-Code, sodass man annehmen kann, dass das Typsystem über Task-Grenzen hinweg funktioniert
Der Kernel erlaubt keinerlei Unsinn
- Unter Unix führt ein Verstoß gegen die Vorbedingungen eines Systemaufrufs dazu, dass dem Aufrufer ein Fehlercode zurückgegeben wird; in Hubris wird der Task dagegen sofort zerstört
- Der Hubris-Kernel übermittelt Fehler an Tasks, die Kernel-Regeln verletzen, über das Konzept des Synthetic Fault
- Tritt in Hubris ein Hardware- oder Synthetic Fault auf, wird der Task sofort gestoppt und kann nicht wiederhergestellt werden
Auch der Server erlaubt keinerlei Unsinn
- Über den dreizehnten und ungewöhnlichsten Systemaufruf, REPLY_FAULT, kann ein Server einen Fehler an den Client übermitteln
- REPLY_FAULT ähnelt REPLY, doch statt eine Nachricht zu übermitteln und den Task wieder ausführbar zu machen, übermittelt es einen Fehler und stoppt den Task
- Mit REPLY_FAULT lässt sich unnötige IPC-Fehlerbehandlung vermeiden. Normale Programme verhalten sich so, als könnten Probleme gar nicht auftreten, und abnormale Programme bekommen nicht einmal die Gelegenheit, Fehler zu behandeln
- REPLY_FAULT bietet zudem eine neue Möglichkeit, anwendungsspezifische Fehler wie Zugriffskontrollregeln zu definieren und umzusetzen
Meinung von GN⁺
- REPLY_FAULT ist ein mächtiger Mechanismus, mit dem ein Server auf dem Client einen Cross-Process-
panic! auslösen kann, ohne dass der Client kooperieren muss. Dadurch wird Hubris zu einem System, das bösartigen Programmen sehr feindselig gegenübersteht
- Ein Nachteil von REPLY_FAULT ist, dass Fuzzing sehr schwierig wird. Ein Chaos-Engineering-Task, der zufällige IPCs oder Systemaufrufe erzeugt, wird bei fast jedem Verhalten sofort zurückgesetzt
- Da normale Hubris-Tasks IPC-Nachrichten nicht dynamisch erzeugen, können sie arbeiten, ohne sich der Existenz von REPLY_FAULT überhaupt bewusst zu sein
- Über REPLY_FAULT kann ein Server beim Client willkürlich Fehler auslösen, doch die Bewertung davon ist noch nicht vollständig abgeschlossen
- Die aggressive Fehlerbehandlung von Hubris hilft dabei, Fehler früh in der Entwicklung zu finden, und macht es anders als bei Fehlercodes unmöglich, Fehler einfach zu ignorieren
- Die Verwendung einer allgemeinen Methode zur Behandlung von IPC-Fehlern kann auch bei normalen Programmen unnötigen Overhead erzeugen. REPLY_FAULT scheint dies zu vermeiden und zugleich bei abnormen Programmen strikt durchzugreifen, was wie eine elegante Lösung wirkt
1 Kommentare
Hacker-News-Kommentare
Zusammengefasst ergibt sich Folgendes:
Es werden Bedenken geäußert, ob sich
REPLY_FAULTkaskadenartig fortpflanzt und welche Verwundbarkeiten daraus entstehenREPLY_FAULTvon C auch A beendet wirdSENDeine zyklische Struktur bildet, könnte man sich unbeabsichtigt sogar selbst beendenREPLY_FAULTbietet eine Möglichkeit, anwendungsspezifische Fehler wie Zugriffskontrolle zu definieren und zu implementierenIn Systemen, in denen ein Team den gesamten Code schreibt, kann das Entfernen verdächtiger Clients die Iterationsgeschwindigkeit erhöhen
Hubris kann als ein Kernel betrachtet werden, der Server Effekte ausführen lässt, die Clients nicht verarbeiten können
Hubris und Humility sind Technologien, in die man sich gern tief einarbeiten würde, was aber durch Zeit- und Verpflichtungsgrenzen erschwert wird
In einem Aprilscherz-RFC zu HTTP wird der HTTP-Statuscode 499 mit der Bedeutung „Sie sollten sich schämen“ vorgeschlagen
Unter Verweis auf Einsteins Zitat „So einfach wie möglich, aber nicht einfacher“ wird angemerkt, dass das Design von Hubris gegen den zweiten Teil verstößt
Humility ist ein großartiger Name für einen Debugger
Unter Linux kann man nicht allein über Sockets direkt andere Programme beenden, aber mit Root-Rechten lassen sich andere Prozesse beenden oder sogar Neustarts auslösen
Das steht in gewissem Widerspruch zur klassischen Weisheit aus Netzwerksystemen: „Sei großzügig beim Annehmen und strikt beim Senden“