1 points par GN⁺ 3 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Depuis Linux 6.9, un outil qui verrouille les disques lors de la mise en veille d’un ordinateur portable échouait silencieusement, laissant en mémoire les clés de chiffrement complet de disque LUKS
  • La cause est une interaction inattendue entre le refactoring de l’accès aux périphériques bloc intégré à Linux 6.9 en mai 2024 et le code de chiffrement ; le correctif proposé tient en une ligne
  • Le problème n’apparaissait pas lors d’un arrêt complet, mais en suspend-to-RAM les clés restaient présentes, ce qui mettait un attaquant ayant saisi un ordinateur portable encore alimenté en position de les extraire de la RAM
  • La découverte a commencé lors du nettoyage du port NixOS de cryptsetup-suspend de Debian, en observant des entrées dans /proc/keys ; un dump mémoire QEMU a confirmé qu’une volume key qui aurait dû être effacée restait présente
  • Des tests d’intégration NixOS et un patch d’avertissement pour cryptsetup ont été proposés ; les fonctions de sécurité comme la suppression des clés juste avant la mise en veille peuvent sembler fonctionner normalement, mais il est facile de manquer leur échec sans vérification réelle de la mémoire

Le problème des clés LUKS restant présentes pendant la suspension depuis Linux 6.9

  • Depuis Linux 6.9, c’est-à-dire depuis mai 2024, un outil qui verrouille les disques lors de la mise en veille d’un ordinateur portable échouait silencieusement
  • Le chiffrement complet de disque LUKS sert à protéger les données en cas de perte, saisie ou vol d’un ordinateur portable, mais dans ce cas les clés de chiffrement restaient en mémoire pendant la mise en veille
  • Cela fonctionnait toujours lors d’un arrêt complet, mais l’impact est important car les portables sont souvent laissés en suspend-to-RAM plutôt qu’entièrement éteints
  • Si quelqu’un mettait la main sur un ordinateur portable encore sous tension, les clés restées en mémoire pouvaient être exposées
  • VeraCrypt a été mentionné comme logiciel remplissant le même rôle sous Windows, mais un commentaire ultérieur a corrigé que “canonical software” ne signifiait pas le logiciel le plus utilisé, mais une recommandation de référence dans le domaine de la sécurité informatique

Cause et patch d’une ligne

  • La cause était le commit de refactoring du noyau Linux md: port block device access to file
    • Le changement lui-même était un refactoring raisonnable et utile, mais il a provoqué une interaction à distance avec le code de chiffrement
  • Le correctif proposé est un patch d’une ligne
  • L’auteur du patch indique que, sans vérification formelle, il ne peut pas affirmer que ce patch est correct ni qu’il n’existe pas d’autres interactions à distance
  • Des travaux de suivi pour éviter une récidive ont aussi été proposés

Processus de découverte

  • Le point de départ était un travail de nettoyage du port NixOS de cryptsetup-suspend de Debian
  • L’original Debian comme le port NixOS présentaient tous deux une condition de concurrence gênante mais non nuisible, qui empêchait parfois l’ordinateur portable de se mettre en veille
  • Pour résoudre cela, il a été tenté de ressusciter le patch noyau non fusionné de Pali Rohár, dm-crypt suspend/hibernation key wiping patch
  • En examinant alors le code source de cryptsetup et du noyau, il a été constaté que, d’après la documentation, le keyring est attaché au thread appelant et supprimé lorsque ce thread se termine
  • Mais des entrées apparaissaient dans /proc/keys, qui n’était pas connu auparavant, ce qui a renforcé les soupçons
  • Finalement, une machine virtuelle QEMU a été lancée et sa mémoire dumpée, confirmant que la LUKS volume key qui aurait dû être effacée était toujours présente

Projet secure suspend-to-RAM pour NixOS

  • Le projet secure-suspend, publié séparément, fournit un secure suspend-to-RAM expérimental pour NixOS
  • Avec le chiffrement complet de disque classique, lorsque l’ordinateur portable est en veille, les clés restent en mémoire, ce qui peut le rendre vulnérable aux cold boot attacks ou aux techniques d’exfiltration de RAM
  • Ce projet ressuscite l’ancien patch noyau de Pali Rohár afin d’effacer les clés de chiffrement LUKS lors de la mise en veille
  • Il s’inspire de cryptsetup-suspend de Debian, mais utilise un patch noyau pour éviter la condition de concurrence qui empêche parfois le portable de se mettre en veille, et ajoute des mesures préventives supplémentaires
  • Il prend entièrement en charge les root filesystems chiffrés et fournit aussi des tests d’intégration
  • Le patch noyau et les outils en espace utilisateur peuvent être adaptés à d’autres distributions Linux
  • Le projet est publié sous le nom secure-suspend

Pourquoi la vérification de la sécurité de la suspension est difficile

  • Le fait de voir l’écran de verrouillage après une mise en veille ne signifie pas que le périphérique de stockage a réellement été verrouillé
  • Si le disque est immédiatement accessible juste après la sortie de veille, cela indique que le périphérique de stockage n’a jamais été verrouillé
    • Par exemple, on peut vérifier l’accès au disque avec un script qui continue de tourner derrière l’écran de verrouillage
    • S’il est possible de se connecter par clé publique SSH après la mise en veille sans d’abord déverrouiller le stockage chiffré, il est facile de confirmer que le périphérique de stockage n’a pas été verrouillé
  • Certains commentaires indiquent que les configurations par défaut d’Ubuntu ou Debian n’ont même pas tenté de fournir une telle protection
  • Il faut vérifier séparément si la tentative de verrouillage du stockage a réellement fonctionné correctement
    • Les horodatages des logs peuvent avoir été générés avant la mise en veille mais écrits après le réveil
    • À l’inverse, des logs créés juste après le réveil, avant l’ajustement de l’heure système, peuvent sembler dater du moment de la mise en veille
  • Que le verrouillage du stockage ait lieu juste avant la mise en veille ou juste après la reprise peut sembler identique pour l’utilisateur, mais c’est une différence décisive du point de vue de la sécurité
  • Le test d’intégration NixOS démarre le système dans une machine virtuelle puis dumpe la mémoire afin de vérifier que la clé a bien été effacée pendant la mise en veille

1 commentaires

 
GN⁺ 3 시간 전
Avis de Hacker News
  • C’est bien un bug intéressant, mais le titre donne un peu l’impression d’être du clickbait
    D’après ce que j’ai compris, cryptsetup luksSuspend est plutôt une extension créée par Debian qu’une fonctionnalité officiellement prise en charge, donc j’ai l’impression que cette régression n’a touché que Debian
    Je ne sais pas trop si l’on peut reprocher au noyau un problème sur une fonctionnalité qui n’est ni prise en charge ni largement testée
    Cela dit, c’est impressionnant, et c’est une bonne chose que des tests aient été ajoutés pour éviter que cette régression ne réapparaisse. Je suis aussi d’accord avec l’avis de l’OP selon lequel NixOSTests est vraiment excellent
    Mais à lire le titre seul, on a l’impression d’un problème répandu, et pas limité à une distribution précise

    • Je visais un titre techniquement exact, pas une incitation au clic
      C’est vrai. Les personnes qui utilisent la configuration par défaut ne sont pas affectées, puisqu’elles ne s’attendent de toute façon pas à ce que la clé du volume soit en sécurité pendant la suspension
      La solution de Debian a été portée vers plusieurs autres distributions, probablement la plupart, et il devait aussi y avoir pas mal de gens maintenant leurs propres ports
      La page de manuel thread-keyring(7) promet que « le trousseau de clés du thread est détruit quand le thread qui le référence se termine »
      Le projet cryptsetup s’appuyait sur cette propriété dans le mécanisme qui fait passer les clés de l’espace utilisateur à l’espace noyau, mais le noyau 6.9 a introduit une régression qui a cassé cette propriété
    • Je ne comprends pas pourquoi on dit que c’est spécifique à Debian. luksSuspend est une fonctionnalité upstream, ajoutée dans la version v1.1.0 en 2009
      Je l’ai déjà utilisé de temps en temps sur Arch et openSUSE, et il existe clairement aussi dans des distributions autres que Debian
      Vous pensez probablement à l’intégration automatique avec la suspension système, mais ce n’est pas le cœur du sujet. luksSuspend est documenté comme supprimant les clés de la mémoire système, et ce comportement a cessé de fonctionner à cause du patch de refactorisation concerné dans Linux 6.9
      Cela dit, en pratique, on peut aussi voir cela comme un bug côté cryptsetup. Il dépendait d’un comportement de durée de vie très précis des clés du keyring du noyau, et on peut soutenir qu’il aurait dû les effacer plus explicitement depuis l’espace utilisateur
      [1]: https://gitlab.com/cryptsetup/cryptsetup/-/commit/3cea5dcc7b...
      [2]: https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/docs/v1...
      [3]: https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/93...
    • La sous-commande se trouve dans le dépôt officiel de cryptsetup et sa description semble bien correspondre : https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/man/cry...
    • J’ai utilisé cette fonctionnalité sur Arch, et elle est utilisable aussi avec un LUKS standard. À ma connaissance, elle n’est toutefois pas utilisée par défaut lors de la suspension
      Vous parlez probablement des machines qui, après luksSuspend, déclenchent une suspension RAM d’une manière réellement utile ; cela visait Debian au départ, puis c’est arrivé aussi sur Arch, mais dans les deux cas ce n’était pas le comportement par défaut
    • Je me demande dans quelle version Debian 6.9 a été déployé pour la première fois
  • Je ne vois pas bien d’autre méthode. Avec la veille, c’est-à-dire le RAM suspend, tout est stocké en RAM et chiffré, mais il me semble que la clé maître reste dans la mémoire du noyau
    En revanche, avec l’hibernation, c’est-à-dire la suspension sur disque, tout le contenu de la RAM, y compris la clé maître, est écrit sur le disque, chiffré, puis la RAM est effacée
    Au réveil, il faut ressaisir la phrase de passe afin de déchiffrer la clé maître et de recharger le contenu du disque en mémoire

    • Exact. Sur la plupart des distributions Linux par défaut, si vous suspendez simplement votre ordinateur portable, tout reste en mémoire, y compris la clé maître
      Mais Debian a d’abord créé un module optionnel cryptsetup-suspend, qui exécute la commande luksSuspend censée effacer les clés de la mémoire, puis redemande la phrase de passe à la reprise
      Jusqu’au noyau 6.8, cela fonctionnait comme décrit, mais à partir du noyau 6.9, cela a cessé de fonctionner silencieusement
    • Les CPU Intel/AMD des cinq dernières années environ prennent tous deux en charge le chiffrement complet de la mémoire, transparent pour le système d’exploitation
      Si cette fonction est activée, les attaques par démarrage à froid appartiennent au passé. Elle est généralement désactivée par défaut parce qu’elle réduit les performances de la RAM d’environ 0,5 %
  • Puisqu’on ne ressaisit pas le mot de passe de démarrage après une sortie de veille, la clé de chiffrement est forcément encore en mémoire

    • Il est évident que la distribution n’utilise pas cryptsetup-luksSuspend
  • Ce n’est pas un problème qui me préoccupe beaucoup
    La seule raison pour laquelle j’utilise le chiffrement de disque, c’est pour ne pas avoir à craindre que quelqu’un fouille dans mes documents fiscaux ou mes informations de carte bancaire quand je vends mon ordinateur portable
    Bien sûr, j’efface aussi l’ordinateur, mais si les données sont chiffrées au niveau du disque, j’estime que le risque de les récupérer avec des outils d’analyse forensique, par exemple, est très faible

    • Comme compromis raisonnable, il suffit aussi d’effacer seulement l’en-tête LUKS
      LUKS utilise un algorithme anti-forensique qui exige la clé de volume complète pour ouvrir le disque. Les blocs de clé sont combinés par un algorithme de diffusion puis XORés pour produire la véritable clé maître ; en théorie, effacer un seul secteur de la clé de volume devrait rendre l’ensemble irrécupérable
      Autrement dit, s’il manque ne serait-ce qu’un bloc de la clé, on ne peut pas facilement deviner le reste
    • En supposant que la clé de chiffrement soit forte, l’effacement est théoriquement redondant
  • Je ne suis absolument pas expert en sécurité, mais quand on voit ces derniers temps des failles de sécurité critiques découvertes régulièrement, du genre « une ligne de vérification en C, à cheval sur plusieurs fichiers, oubliée pendant un refactoring », le postulat même d’une énorme base de code C open source sûre me paraît douteux
    Ce n’est pas un problème propre au C, mais il me semble qu’en C, en particulier, il est plus difficile d’imposer et de suivre des invariants de manière cohérente, surtout lors de changements de code
    Je ne sais pas non plus si la programmation fonctionnelle, qui encode les invariants dans les types, est une solution réellement extensible. Model checking ? fuzzing par LLM ? Moins de primitives, avec des frontières plus nettes ? seLinux a-t-il été « vérifié » de cette façon ?

    • Les inconvénients du C sont visibles et je ne le recommanderais généralement pas pour de nouveaux projets, mais je ne vois pas ce bug précis comme un bon exemple de quelque chose que le borrow checker de Rust, ou le système de types d’un autre langage, aurait détecté. Je ne pense pas non plus qu’un analyseur statique l’aurait trouvé
      En gros, c’est de cet ordre :
      original: DoTheThing()
      new: DoTheThingSlightlyDifferentButKeepMyCredentialsAlive()
      fix: DoTheThingSlightlyDifferentButDoInFactNOTKeepMyCredentialsAlive()
      D’expérience, une grande partie des bugs difficiles viennent de violations d’invariants système de haut niveau, et ce n’est pas le genre de chose qui me semble automatisable
      Même avec quelque chose comme Lean, on peut prouver qu’un programme satisfait une propriété donnée, mais encore fallait-il avoir pensé à cette propriété au préalable. La preuve ne découvre pas les invariants à votre place
      Si l’on avait pensé à la propriété de sécurité pertinente, il n’aurait sans doute pas été difficile d’écrire un test de régression. À mon avis, la vraie difficulté n’est pas d’exprimer l’implémentation de façon sûre, mais de comprendre qu’il existe une propriété que l’implémentation doit préserver
    • Le postulat d’une base de code publique sûre tient en soi
      Le problème est qu’une meilleure auditabilité ne signifie pas automatiquement qu’il y aura davantage d’audits
      Il faut que des personnes suffisamment compétentes y consacrent suffisamment de temps
    • Même traduit en Rust, cela aurait donné « on a oublié une ligne de vérification en Rust »
      C’est un bug dû au croisement de préoccupations et à un manque de connaissance inter-domaines. En Lisp ou en assembleur, cela aurait probablement été pareil
    • La leçon à en tirer ici, c’est que si une fonctionnalité n’a pas au moins des cas de test associés, ce n’est pas une vraie fonctionnalité
    • Le postulat d’une « énorme base de code C open source sûre » paraît douteux parce que la revue de code n’est parfois pas très différente d’un problème de l’arrêt idéalisé, avec accès à une version formalisée de la spécification
      Autrement dit, il n’existe pas de définition rigoureuse de ce qui constitue un problème de sécurité
  • Une agence fédérale avait-elle désespérément besoin d’un moyen d’obtenir les clés ? Est-ce une bugdoor ? Le commit a-t-il été retracé ?
    J’ai vu beaucoup de schémas de ce genre récemment, et je commence à devenir un peu méfiant. C’est peut-être aussi simplement parce que les gens y sont plus sensibles et les signalent davantage

    • C’est une régression. L’application en espace utilisateur aurait elle aussi échoué silencieusement, et c’est le résultat d’une succession de négligences
      Le fait que la clé de chiffrement soit en mémoire ne signifie pas forcément qu’elle peut être extraite. C’est plutôt qu’elle est restée inutilement et indéfiniment à un endroit où elle n’aurait pas dû se trouver
  • Ce genre de régression est facile à rater, parce que tout continue à « fonctionner ». Les bugs de sécurité ne se manifestent pas souvent d’eux-mêmes

    • Exact. C’est pour cela que les tests d’intégration sont encore plus importants pour ce type de fonctionnalité
      C’était aussi intéressant à écrire, et cela a permis de lancer git-bisect pour trouver le refactoring précis du noyau qui a introduit ce bug : https://github.com/NixOS/nixpkgs/pull/532499
  • Sur mon ordinateur portable Fedora, j’ai configuré Linux pour hiberner sur disque 15 minutes après la mise en veille. Si l’on coupe l’alimentation de la mémoire, ce bug spécifique à Debian n’est plus un problème
    L’extension des outils Linux par Debian est séduisante en théorie, mais si l’on s’inquiète vraiment des attaques par cold boot, il faut effacer de la mémoire non seulement les clés LUKS, mais aussi toutes les clés et tous les documents importants
    Donc, au final, la seule vraie façon de se protéger contre le cold boot, c’est l’hibernation

    • D’accord. Ou alors, on peut ressusciter FridgeLock : https://www.sec.in.tum.de/i20/publications/fridgelock-preven...
    • Mais au moment de la reprise, où récupère-t-on la clé pour déchiffrer la mémoire ?
      À ma connaissance, ce n’est pas pratique sans utiliser un TPM. Et avec un TPM, on remet en fait son destin entre les mains du TPM
  • Il suffit d’imaginer à quoi aurait ressemblé ce fil HN si cette vulnérabilité avait été présente dans un système d’exploitation commercial
    Le commentaire le plus haut aurait certainement dit qu’Applosoft ne se soucie plus de la qualité logicielle, ou que « voilà ce qui arrive quand on laisse entrer les déchets de vibe coding dans l’OS »
    Les commentaires en dessous auraient été des théories du complot sur le complexe industriel de la surveillance et la NSA ; ailleurs ce serait délirant, mais pas sur HN

  • Je ne comprends pas pourquoi quelque chose d’aussi important n’est pas testé à chaque build