Wie wir Cranelift auf Herz und Nieren prüfen, um in Compute sicheres Sandboxing zu bieten
2019 haben wir die Bytecode Alliance mit ins Leben gerufen. Ziel dabei war die Gründung einer Open-Source-Community, die auf WebAssembly Compiler-Tools und Basistechnologien entwickelt, die mit verschiedenen Plattformen kompatibel sind.WebAssembly ist der Grundpfeiler unserer Serverless-Compute-Umgebung Compute, und wir investieren weiterhin in die Zukunft dieser Programmiersprache, da darin entwickelte Programme mehr Sicherheit bieten als nativer Code.
Heute möchten wir Ihnen Cranelift vorstellen, eine wichtige Sicherheitskomponente unserer WebAssembly Implementierung. Es handelt sich dabei um einen Open-Source-Code-Generator der nächsten Generation, der gemeinsam mit WebAssembly echte Sandbox-Sicherheit bietet.
In einem vor Kurzem erschienenen Post konnten Sie lesen, wie wir ein bestimmtes Sicherheitsproblem in Cranelift entdeckt haben und darauf reagieren konnten, bevor Exploits entwickelt wurden. In diesem Post berichten wir über verschiedene Möglichkeiten, wie wir proaktiv und kontinuierlich nach derartigen Problemen suchen – und zwar sowohl bei gezielten und sicherheitsspezifischen Prüfungen als auch als Teil unseres normalen Entwicklungsprozesses. Wir sind fest davon überzeugt, dass Software nur dann wirklich sicher ist, wenn während der gesamten Entwicklungszeit mithilfe einer Vielzahl an Tools und Methoden auf Sicherheit geachtet wird.
In diesem Post geht es um zwei solcher Methoden. Wir erläutern, wie man „Fuzzing“ (auch als „Testmethodologie“ bekannt) einsetzt und wie wir vor Kurzem eine vollständige Sicherheitsbewertung beim neuen Code-Generierungs-Backend von Cranelift durchgeführt haben. Zunächst aber einige weitere Informationen dazu, was Cranelift genau ist und wie wir es allmählich verbessern.
Was ist Cranelift?
Cranelift ist ein Generator für nativen Code, der die architekturunabhängige Beschreibung eines Programms und schnell nativen Code für den jeweils eingesetzten Prozessor generiert. Für die Arbeit der Bytecode Alliance und ihre Suche nach einer sicheren und effizienten Grundlage für die Programmierung von Software ist er von entscheidender Bedeutung.
Cranelift war ursprünglich als mögliche Ergänzung des Compiler-Backends von Firefox gedacht. In der Zwischenzeit hat das Cranelift-Team die Engine so ausgestattet, dass sie für viele Kontexte außerhalb von Firefox von Nutzen ist. Die Bytecode Alliance baut die Community der Nutzer und Beitragenden von Cranelift weiter aus, darunter auch für die WebAssembly Engines auf Basis von Cranelift wie die Laufzeitumgebungen Lucet und Wasmtime. Zusammen mit der Bytecode Alliance arbeiten wir auch aktiv an Verbesserungen bei Performance und Sicherheit, was allen Nutzern dieses Projekts zugute kommt.
Sicheres Sandboxing für Compute
So funktioniert’s? Mit Cranelift können WebAssembly Engines ein wenig vertrauenswürdiges WebAssembly Programm in sicheren, in Sandboxes isolierten Maschinencode kompilieren. Während Cranelift den Original-Code von WebAssembly in Maschinencode konvertiert, werden Sicherheitsprüfungen eingefügt, die gleichzeitig mit dem Code ausgeführt werden. Deshalb ist es wichtig, mit in den Code integrierten Sandbox-Checks zu überprüfen, ob der Original-Code von WebAssembly in korrekten Maschinencode konvertiert wurde. Wie bereits in einem kürzlich erschienen Post erwähnt, gibt es weitere Sicherheitsmaßnahmen, wenn diese Prüfungen fehlschlagen (auch wenn wir uns auf lange Sicht nicht auf diese Sicherheitsmaßnahmen verlassen wollen).
Damit kann Compute seine Services effizient und mit sehr schnellen Startzeiten ausführen. Möglich wird dies, weil wir zum Trennen der unterschiedlichen Services und Anfragen leichte Inline-Sandbox-Checks im nativen Code nutzen, statt uns auf Betriebssystemprozesse (z. B. moderne Browser oder bestimmte gemeinsame Hosting-Plattformen), Container (z. B. zahlreiche Serverless-Cloud-Angebote) oder vollständige virtuelle Maschinen (z. B. herkömmliches, nicht-gemanagtes Cloud-Hosting) zu verlassen. Dabei kann der native Code von unterschiedlichen Services auf einem einzigen Betriebssystemprozess sicher koexistieren.
Wir arbeiten hart daran, die Code-Kompilierung durch Cranelift so zu gestalten, dass alle Sandbox-Checks für die Sicherheit erhalten bleiben, und Cranelift zugleich schnell genug für unsere Kunden ist, um es jeder einzelnen Webanfrage an ihre Websites vorzuschalten.
Das Testverfahren: Fuzzing und Sicherheits-Audits
Wie bereits festgestellt, ist eine richtige Code-Kompilierung für die Sicherheit der Services unserer Kunden von höchster Bedeutung und jede Fehlkompilierung ist eine ernste Angelegenheit. Wie können wir sicher sein, dass der Compiler diesem Standard wirklich gerecht wird?
Die erste Methode, die wir verwenden, heißt „Fuzzing“. Es handelt sich dabei um eine Form des Testens, bei der das Programm mit dem Ziel, es zum Absturz zu bringen, mit einer Vielzahl von unerwarteten Inputs bombardiert wird – ein sehr wirkungsvoller Test, da die wahllosen Inputs Grenzfälle verursachen, auf die Tester beim Schreiben manueller Tests nie kommen würden. Ein gutes Fuzzing-Framework beobachtet dabei, wie das Programm auf diese Inputs reagiert, und spürt alle möglichen Ausnahmefälle im Programm auf (auch als „feedbackgesteuertes Fuzzing“ bekannt. Durch diese systematische Vorgehensweise lassen sich bislang übersehene Bugs auf erstaunliche Weise offenlegen.
Mozilla hat Cranelift bereits einem starken Fuzzing unterzogen, aber auch wir führen unsere eigenen Tests durch. Auch heute noch durchläuft der Compiler ein ständiges Fuzzing, da das Wasmtime-Projekt am Infrastruktur-Fuzzing-Projekt von Googles OSS-Fuzz teilnimmt. Tatsächlich handelt es sich um das erste Projekt, das weitgehend in Rust geschrieben und ins OSS-Fuzz Programm aufgenommen wurde. Beim Versuch, das fuzzingbasierte Testen von Cranelift zu verbessern, haben wir Code hinzugefügt, um die auf Cranelift basierende Ausführung mit einem WebAssembly Interpreter und die verschiedenen Cranelift Backends miteinander zu vergleichen, die richtige Registerzuteilung symbolisch zu belegen und vieles mehr. Die Bytecode Alliance hat festgestellt, dass sich Compiler- und Laufzeit-Bugs mit Fuzzing besonders effektiv aufspüren lassen, was wir nur bestätigen können!
Wir haben uns auch mit der Sicherheitsfirma Atredis Partners zusammengetan, um eine gezielte Sicherheitsbewertung durchzuführen. Bei dieser Evaluierung ging es um manuelle, statische Analysen und dynamische Tests. Sie konzentrierte sich auf Registerzuteilung, Anweisungscodierung und Optimierung und alle potenziellen Angriffsflächen, bei denen die Laufzeit mit dem generierten Code in Verbindung steht. Die Bewertung umfasste eine Untersuchung der bestehenden Fuzzing Tools, um alle Arten von Code miteinzubeziehen. Bei der Bewertung stellte man fest, dass die Laufzeitumgebung Lucet und das neue Cranelift Backend gut entwickelt und implementiert wurden und Testverfahren wie Fuzzing angemessen nutzten.
Aus vielen Teilen wird ein Ganzes
Wir setzen beim Entwickeln des Compilers und seiner Integrationen in die größeren Systeme (wie etwa Lucet) weiterhin stark auf Tests und Verifizierung. In Verbindung mit den von uns eingerichteten (menschlichen und technischen) Prozessen für schnelle Reaktionen auf Bugs sind wir zuversichtlich, dass Cranelift als zuverlässige, schnelle und sichere Komponente unserer Serverless-Compute-Umgebung dienen kann. Während Cranelift weiterhin Sandboxing für Compute unterstützt, investieren wir nach wie vor in Geschwindigkeit und Qualität, wovon unsere Kunden und die weitere Open-Source-Community als Ganzes profitieren.