Folgen des Umschreibens von Firefox-Komponenten in Rust

In früheren Artikeln der Serie haben wir die Speichersicherheit und die Thread-Sicherheit in Rust erörtert. In diesem letzten Artikel werden die Auswirkungen einer echten Rust-Anwendung mithilfe des Quantum CSS-Projekts untersucht .

Die CSS-Engine wendet CSS-Regeln auf die Seite an. Dies ist ein absteigender Prozess, der den DOM-Baum absteigt. Nach der Berechnung des übergeordneten CSS können die untergeordneten Stile unabhängig berechnet werden: ideal für paralleles Rechnen. Bis 2017 unternahm Mozilla zwei Versuche, das Stilsystem mit C ++ zu parallelisieren. Beides ist fehlgeschlagen.

Die Entwicklung von Quantum CSS hat begonnen, die Produktivität zu steigern. Die Verbesserung der Sicherheit ist nur ein guter Nebeneffekt.


Es besteht ein bestimmter Zusammenhang zwischen Speicherschutz- und Informationssicherheitsfehlern. Daher haben wir erwartet, dass die Verwendung von Rust die Angriffsfläche in Firefox verringern würde. Dieser Artikel befasst sich mit potenziellen Schwachstellen, die seit der ersten Veröffentlichung von Firefox im Jahr 2002 in der CSS-Engine identifiziert wurden. Dann schauen Sie sich an, was mit Rust hätte verhindert werden können und was nicht.

In der CSS-Komponente von Firefox wurden für alle Zeiten 69 Sicherheitsfehler festgestellt. Wenn wir eine Zeitmaschine hätten und sie von Anfang an Rust schreiben könnten, wären 51 (73,9%) Fehler unmöglich. Obwohl Rust das Schreiben von gutem Code erleichtert, bietet es auch keinen absoluten Schutz.

Rost


Rust ist eine moderne Systemprogrammiersprache, die für Typen und Speicher sicher ist. Als Nebeneffekt dieser Sicherheitsgarantien sind Rust-Programme auch beim Kompilieren threadsicher. Somit ist Rust besonders geeignet für:

  • sichere Verarbeitung unzuverlässiger eingehender Daten;
  • Parallelität zur Verbesserung der Leistung;
  • Integration einzelner Komponenten in die bestehende Codebasis.

Rust behebt jedoch einige Fehlerklassen, insbesondere Korrektheitsfehler, nicht explizit. Tatsächlich haben unsere Ingenieure beim Umschreiben von Quantum CSS versehentlich einen kritischen Sicherheitsfehler wiederholt, der zuvor in C ++ - Code behoben wurde. Sie haben versehentlich den Fehlerfix 641731 gelöscht, der das Durchsickern des globalen Verlaufs über SVG ermöglicht. Der Fehler wurde als Fehler 1420001 erneut registriert. Ein Verlaufsleck wird als kritische Sicherheitslücke eingestuft. Die anfängliche Korrektur war eine zusätzliche Überprüfung, um festzustellen, ob das SVG-Dokument ein Bild ist. Leider wurde diese Prüfung beim Umschreiben des Codes übersehen.

Obwohl automatisierte Tests Verstöße gegen die Regel feststellen sollten :visited , aber in der Praxis haben sie diesen Fehler nicht gefunden. Um automatische Tests zu beschleunigen, haben wir den Mechanismus, der diese Funktion getestet hat, vorübergehend deaktiviert. Tests sind nicht besonders nützlich, wenn sie nicht durchgeführt werden. Das Risiko einer erneuten Implementierung logischer Fehler kann durch eine gute Testabdeckung verringert werden. Es besteht jedoch weiterhin die Gefahr neuer logischer Fehler.

Wenn ein Entwickler mit Rust vertraut wird, wird sein Code noch sicherer. Obwohl Rust nicht alle möglichen Schwachstellen verhindert, behebt es eine ganze Klasse der schwerwiegendsten Fehler.

Quantum CSS-Sicherheitsfehler


Im Allgemeinen verhindert Rust standardmäßig Fehler in Bezug auf Speicher, Grenzen, null / nicht initialisierte Variablen und ganzzahlige Überläufe. Der oben erwähnte nicht standardmäßige Fehler bleibt möglich: Ein Absturz tritt aufgrund einer fehlgeschlagenen Speicherzuweisung auf.

Sicherheitsfehler nach Kategorie


  • Speicher: 32
  • Grenzen: 12
  • Implementierung: 12
  • Null: 7
  • Stapelüberlauf: 3
  • Ganzzahliger Überlauf: 2
  • Sonstiges: 1
In unserer Analyse beziehen sich alle Fehler auf die Sicherheit, aber nur 43 erhielten eine offizielle Bewertung (sie wird von den Sicherheitsingenieuren von Mozilla basierend auf qualifizierten Annahmen zur "Ausnutzbarkeit" vergeben). Gewöhnliche Fehler können auf fehlende Funktionen oder Fehlfunktionen hinweisen, die nicht unbedingt zu Datenlecks oder Verhaltensänderungen führen. Offizielle Sicherheitsfehler reichen von geringer Bedeutung (wenn die Angriffsfläche stark eingeschränkt ist) bis zu kritischer Sicherheitsanfälligkeit (möglicherweise kann ein Angreifer beliebigen Code auf der Plattform des Benutzers ausführen).

Speicherschwachstellen werden häufig als schwerwiegende Sicherheitsprobleme eingestuft. Von den 34 kritischen / schwerwiegenden Problemen bezogen sich 32 auf das Gedächtnis.

Schweregradverteilung von Sicherheitslücken


  • Gesamt: 70
  • Sicherheitsfehler: 43
  • Kritisch / Ernst: 34
  • Fester Rost: 32

Vergleich von Rust und C ++


Fehler 955913 - Heap-Pufferüberlauf in der GetCustomPropertyNameAt Funktion. Der Code verwendete die falsche Variable für die Indizierung, was zur Interpretation des Speichers nach dem Ende des Arrays führte. Dies kann zu einem Absturz führen, wenn Sie auf einen fehlerhaften Zeiger zugreifen oder Speicher in eine Zeichenfolge kopieren, die an eine andere Komponente übergeben wird.

Die Reihenfolge aller CSS-Eigenschaften (einschließlich benutzerdefiniert, d. H. Benutzerdefiniert) wird im mOrder Array gespeichert. Jedes Element wird entweder durch einen CSS-Eigenschaftswert oder bei benutzerdefinierten Eigenschaften durch einen Wert dargestellt, der mit eCSSProperty_COUNT (Gesamtzahl der nicht benutzerdefinierten CSS-Eigenschaften) beginnt. Um den Namen der benutzerdefinierten Eigenschaften mOrder , müssen Sie zuerst den Wert von mOrder und dann auf den Namen im entsprechenden Index des mVariableOrder Arrays mVariableOrder , in dem die Namen der benutzerdefinierten Eigenschaften der Reihe nach mVariableOrder .

Anfälliger C ++ - Code:


  void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const { MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT); aResult.Truncate(); aResult.AppendLiteral("var-"); aResult.Append(mVariableOrder[aIndex]); 

Das Problem tritt in Zeile 6 auf, wenn mit aIndex auf das Element des mVariableOrder Arrays mVariableOrder wird. Tatsache ist, dass aIndex mit dem mOrder Array verwendet werden sollte, nicht mit dem mVariableOrder . Das entsprechende Element für die benutzerdefinierte Eigenschaft, die von aIndex in mOrder ist tatsächlich mOrder[aIndex] - eCSSProperty_COUNT .

Korrigierter C ++ - Code:


  void Get CustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const { MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT); uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT; aResult.Truncate(); aResult.AppendLiteral("var-"); aResult.Append(mVariableOrder[variableIndex]); } 

Entsprechender Rostcode


Obwohl Rust C ++ etwas ähnlich ist, verwendet es andere Abstraktionen und Datenstrukturen. Der Rostcode unterscheidet sich stark von C ++ (siehe unten für weitere Details). Schauen wir uns zunächst an, was passiert, wenn der anfällige Code so wörtlich wie möglich übersetzt wird:

  fn GetCustomPropertyNameAt(&self, aIndex: usize) -> String { assert!(self.mOrder[aIndex] >= self.eCSSProperty_COUNT); let mut result = "var-".to_string(); result += &self.mVariableOrder[aIndex]; result } 

Der Rust-Compiler akzeptiert diesen Code, da die Länge der Vektoren vor der Ausführung nicht bestimmt werden kann. Im Gegensatz zu Arrays, deren Länge bekannt sein sollte, hat der Typ Vec in Rust eine dynamische Größe. Die Überprüfung der Grenzen ist jedoch in die Implementierung des Standardbibliotheksvektors integriert. Wenn ein ungültiger Index angezeigt wird, wird das Programm sofort auf kontrollierte Weise beendet, um unbefugten Zugriff zu verhindern.

Quanten-CSS- Realcode verwendet sehr unterschiedliche Datenstrukturen, daher gibt es kein genaues Äquivalent. Zum Beispiel verwenden wir die leistungsstarken integrierten Datenstrukturen von Rust, um die Anordnung und die Eigenschaftsnamen zu vereinheitlichen. Dadurch entfällt die Notwendigkeit, zwei unabhängige Arrays zu verwalten. Rostdatenstrukturen verbessern auch die Datenkapselung und verringern die Wahrscheinlichkeit solcher logischen Fehler. Da der Code in anderen Teilen des Browsers mit C ++ - Code interagieren muss, GetCustomPropertyNameAt die neue Funktion GetCustomPropertyNameAt nicht wie GetCustomPropertyNameAt Rust-Code aus. Es bietet jedoch weiterhin alle Sicherheitsgarantien und bietet gleichzeitig eine verständlichere Abstraktion der zugrunde liegenden Daten.

tl; dr


Da Sicherheitslücken häufig mit Sicherheitsverletzungen im Speicher verbunden sind, sollte Rust-Code die Anzahl kritischer CVEs erheblich reduzieren. Aber auch Rust ist nicht perfekt. Entwickler müssen weiterhin nach Korrektheitsfehlern und Datenleckangriffen suchen. Die Unterstützung für sichere Bibliotheken erfordert weiterhin Codeüberprüfungen, Tests und Fuzzing.

Compiler können nicht alle Programmiererfehler abfangen. Trotzdem entlastet Rust unsere Arbeitssicherheit und ermöglicht es uns, uns auf die logische Korrektheit des Codes zu konzentrieren.

Source: https://habr.com/ru/post/de445670/


All Articles