1 points par GN⁺ 2024-03-17 | 1 commentaires | Partager sur WhatsApp
  • Ladybird traite correctement jusqu’à un certain point du contenu web normal, mais l’exécution de Domato, le fuzzer DOM de Google Project Zero, a rapidement révélé des cas limites cachés dans le moteur du navigateur
  • Cinq vrais bugs ont été trouvés et corrigés avec des entrées anormales réalistes, comme un DOM créé en JavaScript en contournant les règles du parseur, des documents sans window, ou des références SVG circulaires
  • Des hypothèses implicites internes, comme supposer un ancêtre table pour ``, une window dans un document DOMParser, ou une erreur de parcours des frères dans Element.before(), ont conduit à des crashs ou à des boucles infinies
  • Le problème d’accès à contentWindow sur une iframe supprimée n’était pas seulement un défaut propre à Ladybird : il touchait aussi aux hypothèses de la spécification HTML sur le browsing context, ce qui a débouché sur une issue WHATWG HTML
  • Les fuzzers comme Domato exposent des problèmes de sécurité et de stabilité difficiles à détecter avec de simples tests de pages web normales ; la prochaine étape pour Ladybird est de se stabiliser assez pour supporter un fuzzing continu, puis de l’automatiser

Stress tester Ladybird avec Domato

  • Ladybird traite assez bien le contenu web bien formé, mais l’objectif était de voir quels problèmes apparaissent en lui injectant des entrées étranges avec un outil de recherche en sécurité
  • L’outil utilisé est Domato, le fuzzer DOM de Google Project Zero
    • Domato génère des pages web aléatoires mêlant du HTML, CSS et JavaScript pour l’essentiel valides, mais étranges
    • Les pages générées ont été chargées dans un build de débogage de Ladybird, puis leur comportement a été observé
  • Comme le README de Domato met en avant les nombreux bugs trouvés dans les principaux navigateurs, il semblait probable de trouver aussi des défauts significatifs dans Ladybird

Déréférencement de pointeur nul quand est dans

  • Le premier problème a été découvert en moins d’une seconde, et une sortie Domato de 562 Kio a pu être réduite à la forme suivante

let mfrac = document.createElement("mfrac");
mfrac.appendChild(document.createElement("th"));
document.body.appendChild(mfrac);

  • Dans un build de Ladybird avec UBSAN activé, l’appel à table_containing_cell dans HTMLTableCellElement.cpp provoquait un déréférencement de pointeur nul
  • La cause venait du fait que les implémentations Ladybird de et supposaient qu’il existait toujours un `` plus haut dans l’arbre DOM
    • Le parseur HTML n’autorise pas un balisage comme ``
    • Un navigateur conforme à la spécification, lorsqu’il charge le balisage ci-dessus, crée un seul `` vide à l’intérieur
    • Mais en créant directement les nœuds via l’API DOM JavaScript, il est possible de contourner une partie des règles du parseur et de placer un dans un
  • Le code en cause servait à implémenter un ancien comportement où et appliquent les bordures et le padding CSS non seulement aux boîtes de table, mais aussi à chaque cellule
  • Le correctif a consisté à supprimer l’hypothèse selon laquelle et ont toujours un ancêtre ``
    • first_ancestor_of_type() est utilisé à la place de table_containing_cell(*this)
    • S’il n’y a pas d’ancêtre table, la fonction retourne immédiatement
    • Le commit de correction est ici

Affectation d’un gestionnaire d’événement `` dans un document sans window

  • Le deuxième problème a lui aussi été découvert en moins d’une seconde, et une sortie Domato de 472 Kio a été réduite au code suivant

var parser = new DOMParser();
var doc = parser.parseFromString("", "text/html");
var body = doc.createElement("body");
body.onblur = null;

  • Ladybird s’arrêtait sur un échec de vérification GCPtr
  • Le point clé est le comportement spécial des attributs de gestionnaires d’événements onfoo de ``
    • Pour la compatibilité avec les anciens contenus web, une affectation à document.body.onfoo doit être transmise à window.onfoo
    • Mais un document créé avec DOMParser n’a pas d’objet window
  • Le modèle d’objets interne de Ladybird était structuré à tort comme si tout document avait toujours une window
  • Après correction, Document::window() renvoie une valeur nullable, et le cas null est traité à plusieurs endroits
    • Dans un document sans window, affecter document.body.onblur ne fait rien, comme dans les autres navigateurs

Référence circulaire dans un `` SVG

  • Le troisième problème était une récursion infinie lorsqu’un dégradé SVG se référençait lui-même

  • SVG doit prendre en charge à la fois les SVG inline dans du HTML et le format d’image externe, et un dégradé peut référencer un autre dégradé pour en hériter les couleurs
  • L’implémentation de Ladybird ne tenait pas compte du cas où un dégradé se référence lui-même, et suivait la chaîne de références en bouclant indéfiniment
  • Bloquer uniquement le cas d’une référence à soi-même ne permet pas de traiter les références circulaires en plusieurs étapes

  • Le bon traitement consiste à suivre tous les dégradés visités et, lorsqu’un dégradé déjà visité est rencontré à nouveau, à interrompre le suivi de la chaîne
  • Firefox affiche une plainte dans la console développeur pour ce type de dégradé

Accès à la propriété window d’une iframe supprimée et bug de la spécification HTML

  • Le quatrième problème se produisait lorsqu’on supprimait une iframe, puis appelait getSelection() sur le contentWindow conservé auparavant

window.onload = function() {
let iframe = document.querySelector("iframe")
let iframeWindow = iframe.contentWindow;
iframe.remove();
iframeWindow.getSelection();
}

  • Ladybird émettait une erreur d’exécution de liaison de référence à pointeur nul vers BrowsingContext dans WindowProxy.cpp
  • Quand une iframe est supprimée du DOM, son content document est détaché de son browsing context
  • Lorsqu’on lit ou écrit une propriété de l’objet window, l’algorithme de la spécification HTML "check if an access between two browsing contexts should be reported" est exécuté
    • Cet algorithme examine le browsing context de la window qui accède et celui de la window cible
    • La spécification suppose à tort qu’au moment de l’accès à la propriété, les deux windows ont un browsing context connecté
  • Une issue a été ouverte pour la spécification HTML, et un contrôle null a d’abord été ajouté à Ladybird
  • Lorsqu’un bug de spécification est trouvé en travaillant sur Ladybird, il est possible d’améliorer la spécification pour tout le monde au moyen d’un rapport de bug ou d’une proposition de correctif

Boucle infinie dans Element.before()

  • Le cinquième problème se manifestait par une page qui ne finissait pas de charger et utilisait 100 % du CPU

two.before(one);

  • La cause était une erreur dans la logique de l’implémentation de before(), qui cherche le premier frère précédent de `` ne faisant pas partie des arguments
  • La boucle existante relisait node->previous_sibling() à chaque itération
while (auto previous_sibling = node->previous_sibling()) {
    // check if previous_sibling is one of the arguments
}
  • En réalité, il fallait parcourir la chaîne des frères en continuant avec previous_sibling->previous_sibling()
for (auto sibling = node->previous_sibling(); sibling; sibling = sibling->previous_sibling()) {
    // check if previous_sibling is one of the arguments
}

Résultats du fuzzing et prochaines étapes

  • Cette session a permis de trouver cinq vrais bugs, dont un bug de la spécification HTML, et tous ont été corrigés
  • Elle a montré que Ladybird s’effondre très vite face à des entrées étranges et inattendues
  • Les fuzzers comme Domato sont une ressource utile pour quiconque veut rendre un logiciel plus robuste
  • La prochaine étape consiste à stabiliser Ladybird jusqu’à ce qu’il puisse supporter des entrées de fuzzing en continu
  • Une fois suffisamment stabilisé, il est prévu de l’exécuter automatiquement quelque part dans le cloud afin de trouver davantage de problèmes

1 commentaires

 
GN⁺ 2024-03-17
Commentaires sur Hacker News
  • Cela montre bien pourquoi il est précieux d’avoir plusieurs implémentations indépendantes d’une spécification.
    Rien qu’avec cet article, une faille dans la spécification a été trouvée, et il y en avait probablement d’autres, ou il y en aura encore.

    • Exact. Nous avons déjà trouvé et signalé de nombreux problèmes dans l’ensemble des spécifications HTML, CSS et JS.
      Pour la santé à long terme de la plateforme web, plusieurs implémentations indépendantes sont importantes, et nous essayons nous aussi de jouer ce rôle.
    • Je me demande pourquoi ce fuzzer n’a pas trouvé de bugs dans les navigateurs populaires.
    • Cette conclusion me semble un peu être un raccourci.
      C’est un peu comme si je tweetais « l’aubergine est mon légume préféré », que quelqu’un me corrigeait en disant « en fait, c’est un fruit », puis que j’en concluais que « la valeur de Twitter est prouvée ».
      Cela ne veut pas dire que ce travail en soi, ni le fait d’avoir plusieurs implémentations d’une spécification, n’ont pas de valeur, mais je ne pense pas que cette implication tienne encore à partir de ce seul exemple.
  • J’aime que ce projet continue de montrer qu’une petite équipe peut créer des choses étonnantes.
    J’imagine qu’il aurait été bien plus difficile de faire ce genre de travail au sein d’une entreprise avec de nombreuses parties prenantes.

    • Le projet est impressionnant, mais je me demande si l’approche consistant à partir de « gérer à peu près correctement le contenu web normal », puis à remonter pour corriger les spécifications, les comportements de facto des navigateurs et les éventuels problèmes de sécurité, peut vraiment mener à un navigateur de production.
      Pour un projet amateur, on peut toujours revenir en arrière et refaire les choses, mais j’ai du mal à ne pas penser que certaines de ces considérations auraient dû être intégrées à l’architecture dès le départ.
  • Ils ont déjà implémenté SVG ? Je suis le projet avec intérêt, il avance beaucoup plus vite que je ne l’aurais pensé.

    • Nous avons implémenté une assez grande partie de la spécification SVG, mais il manque encore beaucoup de choses.
      Les animations, en particulier, constituent un gros manque.
  • Pour l’issue #3, il me semblerait aussi judicieux de fixer une limite de profondeur maximale pour les dégradés qui pointent vers d’autres dégradés.
    Cela ferait une défense en profondeur contre les erreurs ou limites de la logique du type « ai-je déjà vu cette référence ? ».
    Je ne connais pas bien les dégradés SVG, et il existe peut-être une raison légitime d’avoir des chaînes de 1 000 références, mais dans un environnement réel, si je voyais ça, je penserais surtout à une attaque ou à une entrée de fuzzer.

    • Côté défense contre les malwares, on voit constamment ce genre d’abus de structure, et je n’ai jamais vu de cas légitime dépassant cinq niveaux de profondeur.
  • J’écris ce commentaire dans Ladybird.
    Hacker News fonctionne maintenant dans Ladybird.
    J’utilise Ladybird quand je parcours quelques minutes par jour des sites comme Hacker News ou OSnews.
    C’est lent et fragile, mais ça fonctionne. Vu à quel point le projet est jeune, et le fait que littéralement tout ait été écrit à partir de zéro, c’est déjà impressionnant.
    J’ai vraiment hâte de voir Ladybird mûrir.

  • C’est intéressant, mais ça m’agace que presque tous les développeurs s’arrêtent à « trouvé ! commit de correction, terminé ! », comme on le voit dans l’issue #1.
    Il ne faut pas faire ça : il faut comprendre exactement ce qui n’allait pas. Par exemple, si le problème était l’hypothèse selon laquelle « le parent existe forcément », il faut chercher le même type d’erreur dans toute la codebase.
    Il faut faire preuve d’imagination pour trouver où la même chose peut encore se produire. Ce n’est jamais à un seul endroit.
    Si le logiciel moderne est un cauchemar plein de bugs auquel il est difficile de faire confiance, c’est en grande partie à cause de contraintes capitalistes, mais on peut tout de même faire mieux.

  • Je me demande si Ladybird sera présent au Web Engines Hackfest cette année.

  • C’est un peu hors sujet, mais je me demande ce qu’il est advenu des vidéos de hacking sur YouTube.
    Avant, j’attendais les nouvelles vidéos, mais j’ai l’impression de ne plus en avoir vu depuis un moment.

    • Pour être honnête, après avoir publié bien plus de 1 000 vidéos, j’étais un peu épuisé.
      Je publie toujours les vidéos de mise à jour mensuelles, mais plusieurs mois se sont écoulés depuis la dernière vidéo de hacking.
      Cela dit, je travaille toujours sur Ladybird tous les jours, et grâce au généreux sponsoring de Shopify et d’autres l’an dernier, je gère maintenant aussi deux ingénieurs à plein temps.