Du Rust dans le noyau de Windows
Le 02 mai 2023 à 05h00
1 min
Logiciel
Logiciel
David Weston, vice-président de Microsoft et directeur de la sécurité du système d'exploitation Windows, a annoncé l'arrivée de Rust dans le noyau de l'OS à la conférence BlueHat IL 2023 de Tel Aviv, rapporte The Register. Certaines bibliothèques du système d'exploitation sont en cours de réécriture dans le langage de plus en plus adopté dans ce monde industriel pour sa robustesse et sa fiabilité.
« Windows démarrera avec Rust dans son noyau dans les semaines ou les mois à venir, ce qui est vraiment génial » s'est enthousiasmé Weston. Rust permet notamment de sécuriser l'utilisation de la mémoire en s'assurant qu'une référence pointe vers une donnée valide.
Le noyau de Linux, lui, inclut la possibilité de code en Rust depuis la version 6.1 sortie en décembre dernier.
Le 02 mai 2023 à 05h00
Commentaires (50)
Vous devez être abonné pour pouvoir commenter.
Déjà abonné ? Se connecter
Abonnez-vousLe 02/05/2023 à 06h37
Bonne nouvelle !
Bon il ne faut pas se leurrer non plus, on n’est pas près d’avoir un noyau 100% réécrit en Rust. (je suis persuadé qui doit rester des morceaux de code qui ont 40ans de l’époque de NT3)
Le 02/05/2023 à 07h09
J’ai l’impression que l’époque où la volonté de ré-écrire tout le kernel Windows en C♯ est un peu révolu.
“back to the metal”
Le 02/05/2023 à 07h18
Je doute fortement qu’il y ait eu une volonté de réécrire le kernel Windows en C#. Les spécificités et les contraintes d’un kernel le rendent peu compatible avec un langage de haut niveau, et incompatible avec un langage à ramasse-miettes.
Sans oublier que le .net nécessite un runtime. Runtime nécessitant un OS pour fonctionner.
Tu confonds peut être avec les API, où Microsoft aimerait plus ou moins abandonner la dépendance forte à Win32 pour son système, pour que cela devienne une brique optionnelle et non plus obligatoire.
Le 02/05/2023 à 07h18
Euh … ça urait été complètement “con” de réécrire le kernel en C#, vu que le C# en compilé en bytecode, et pas en code “natif” pour les processeurs …
Edit : grillé à quelques secondes 😅
Le 02/05/2023 à 08h57
CoreRt est capable de faire du natif depuis un moment déjà. Et du bare metal aussi, Pour du c#, pas forcement le full runtime / mais tu a déjà de quoi faire.
Je remet pas en cause l’inutilité de réécrire le noyaux en c# pas contre
Le 02/05/2023 à 07h20
Rust commence a faire son chemin dans l’écriture des OS, c’est bien.
On peut seulement regretter qu’il ait fallu attendre 50 ans pour qu’on se dise que le langage C méritait une surcouche syntaxique pour minimiser les erreurs courantes de conception, en particulier les accès aux zones de la mémoire.
Quand on y réfléchit, que de temps perdu en solutions alternatives (parfois hardware !) pour détecter/empêcher les accès invalides à la mémoire et les failles de sécurité qui en découlent.
Le 02/05/2023 à 07h28
Il fait sans doute référence à Singularity où seul le bootstrap et le HAL sont en C/C++. Le kernel est bel et bien en C# (runtime + garbage collector).
Le 02/05/2023 à 08h07
Je l’avais oublié ce projet ^^.
Singularity est un microkernel, pas un kernel, et les opérations de bas niveau sont bien en assembleur/C/C++.
Ce projet n’a jamais eu pour vocation de remplacer le noyau de Windows. C’était seulement un projet de recherche.
Pour chipoter : non. C’est en Sing# (qui est une extension d’une extension de C#).
Le 02/05/2023 à 08h02
Avec quel compilateur Microsoft va-t-il pouvoir compiler Rust ? Je doute qu’ils utilisent Rust LLVM.
Si je ne dis pas de bêtise : le projet analogue pour le noyau Linux ne fonctionne que lorsque celui-ci est compilé avec Clang/LLVM et non GCC.
Le 02/05/2023 à 08h09
Moi ce qui me fascine c’est la vitesse à laquelle le C (et surtout le C++ qui etait uniquement mal vu des guru) ont baissé dans l’opinion des dev-influenceur-twitch-o-twitter en l’espace de 2ans simplement à cause du gain de popularité de Rust.
C’était considéré comme le(s) langage(s) indétrônable pour faire du code performant et maintenant on voit de + en + de troll à leur encontre et d’alternatives qui pop comme des champignons (carbon, zig, odin…)
Le 02/05/2023 à 08h27
On ne vit pas dans le même monde, visiblement.
https://www.lemondeinformatique.fr/actualites/lire-la-popularite-du-langage-c-en-constante-progression-89464.html
Le 02/05/2023 à 08h33
“ont baissé dans l’opinion des dev-influenceur-twitch-o-twitter ”
=> me sort l’index tiobe.
Le 02/05/2023 à 13h02
Désolé, je m’étais arrêté à “dev”. Je ne savais même pas qu’il y avait des influenceurs sur Twitch pour du développement (oui, je suis old school).
Le 02/05/2023 à 09h28
Hmm… non, pas vraiment.
Les dev-influenceurs ne sont pas représentatifs des usages, comme le disent les commentaires ci-dessus. Ces influenceurs cherchent a promouvoir leur nouveau langage de prédilection, mais c’est souvent des langages de niche ou des trucs sémantiquement équivalent à des trucs qui existent déjà…
Le 02/05/2023 à 09h43
Tu peux préciser ? Je me souviens que l’implémentation de la gestion mémoire par le CPU (la fameuse MMU de son premier petit nom) n’est pas apparue sans un besoin à la base. Un vrai besoin s’entend.
Le problème c’est qu’il font le buzz et sont plus visibles que le bon sens. Une fois que c’est réécris il se passe quoi ? Bin juste la maintenance. Prenons pour exemple le kernel de Windows justement… qui date un peu.
Le problème c’est que ces influenceurs plus ou moins en mode opération de com vont susciter des vocations pour Rust et pour un chantier ponctuel. Parce que bon, quand on dit Rust on entend Microsoft en bruit de fond.
Et cela arrangera bien les demandeurs qui vont pouvoir faire pression sur les salaires. En image. Tu mets le coder sur le bord de la route et il a un écriteau : “Will code Rust for food”…
Donc ça arrange qui ?
Le 02/05/2023 à 09h56
Bah tous les trucs qui empêchent les accès non-autorisés à la mémoire: du DEP au MPU, en passant par les techniques d’isolation (MPX…)
Le 02/05/2023 à 09h57
Il faut s’entendre sur ce que sont les opérations bas niveau. Je ne parle pas des drivers. Je parle de tout le nécessaire obligatoire pour faire un kernel aujourd’hui :
Et ça, c’est forcément dans un langage très bas niveau, comme l’assembleur ou le C (même le C++ c’est compliqué, sauf à retirer certaines fonctionnalités comme les exceptions).
Que le kernel propose ensuite des services plus évolués (gestion des processus, système de fichiers, etc.) ou des drivers, oui, ça ça peut être écrit dans des langages plus “haut niveau”.
Mais sur un microkernel, toutes les opérations bas niveau sont dans le kernel à proprement parler. Le reste se trouve dans des “services”.
Le 02/05/2023 à 11h25
Pour la gestion de la mémoire, pas besoin d’un langage de très bas niveau. Il faut juste des pointeurs, ce que C# propose. Pour la couche HAL et la gestion des threads, il faut un accès direct aux registres, et là effectivement ce n’est pas proposé de base par C#, mais on peut imaginer des fonctions spéciales qui sont remplacées à la compilation pour donner l’accès aux registres (c’est déjà le cas pour les registres SSE, AVX, et consors: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.intrinsics.x86.sse?view=net-8.0).
Mais bon, comme ça a été dit à plusieurs reprises déjà, en pratique ça n’a strictement aucun intérêt.
Le 02/05/2023 à 10h01
Le 02/05/2023 à 10h08
je pense que tu amalgame C# (le langage) et C#/MSIL/.net (un programme C# compilé en MSIL qui s’exécute sur le runtime).
Singularity est codé en C# (le langage), mais bien évidemment le “binaire” résultant n’est pa du MSIL qui s’exécute pas sur le runtine .Net. Le binaire résultant c’est du bon vieux langage machine qui s’exécute directement sur le CPU.
imagine cela comme un compilateur “C# –> C/C++ –> x86”.
An Overview of the Singularity Project
https://www.researchgate.net/publication/236160050_An_Overview_of_the_Singularity_Project
Le 02/05/2023 à 11h57
Pas du tout, je connais très bien toutes ces notions et les nuances. Mais je sais aussi que le langage a besoin d’un runtime pour fonctionner (c’est intrinsèque au langage) de par l’absence de gestion de la mémoire (ramasse miettes), de la gestion des exceptions et de la réflexivité (pour ne citer que les aspects principaux).
Non. Il est codé en Sing#. Qui est une extension de Spec#, qui est une extension de C#.
Du coup, une extension d’une extension d’un langage, ce n’est plus le même langage. Sinon, on peut dire C++ c’est une extension de C.
Après une lecture rapide de l’article, on se rend compte qu’il y a un abandon/limitation de nombreuses fonctionnalités (la réflexivité existe dans une forme réduite, les données par référence sont absentes de l’ABI, etc.).
Maintenant, en lisant ce passage :
On se rend compte aussi d’une chose, c’est de l’ambiguïté quant à l’usage du terme “kernel”, où un coup cela désigne uniquement le microkernel, et à d’autre moment, le noyau dans son intégralité (microkernel + ses composants).
Mon propos, depuis le début, ne concerne que le microkernel. L’article précise que le code non vérifiable est justement dans la HAL, le kernel (qui devrait plutôt être microkernel, mais passons) et certaines parties du runtime. Soit… exactement la position que je défends depuis le début.
Le 02/05/2023 à 11h59
Perso, je trouve la nouvelle concernant Rust dans le noyau Windows moins fracassante que celle concernant le remplacement de NTFS par ReFS. Une page se tourne…
Le 02/05/2023 à 15h55
Ah bon? Je l’avais loupé le remplacement NTFS par REFS. Je me demande pourquoi leur choix s’est porté sur REFS et pas ZFS.
Le 02/05/2023 à 12h03
Non. Même si on limite les désallocations de mémoire au sein d’un noyau, il est nécessaire de pouvoir désallouer de la mémoire. Ce que ne permet pas de faire le C#.
De plus, le ramasse-miette génère un problème d’indéterminisme, qui peut être très problématique dans le cadre d’opération de bas niveau / manipulation des registres, etc…
Le 02/05/2023 à 12h25
Peut être qu’il me manque un concept, ou que ma compréhension est erronée. Au niveau du noyau, je ne pense pas qu’il y ait la notion d’allocation/désallocations ? Le code s’exécutant a accès à l’intégralité de la mémoire physique et l’utilise comme bon lui semble. La notion d’allocation/désallocation est un concept apporté par le langage, et malloc/new vont juste permettre d’éviter de s’emmeler. En pratique, je ne vois pas pourquoi malloc/new ne pourraient pas être réimplémentés en C#.
Pareil pour le garbage collector, il “suffit” de ne pas s’en servir. La manière dont je vois les choses, c’est implémenter un malloc qui retourne des ref struct créés à partir d’adresses mémoires arbitraires. Le garbage collector n’y touchera pas.
Le 02/05/2023 à 12h27
Par contre oui, comme je le mentionnais pour la gestion de registre c’est la merde Notamment pour implémenter un handler d’interruption, là ça me parait compliqué.
Le 02/05/2023 à 12h27
Le C aussi a besoin d’un runtime pour fonctionner. le C++ aussi. Et pratiquement tous les langages. Dans le cas du C, le runtime est inséré dans le binaire par le compilateur donc on a tendance à oublier qu’il est là.
google “crt0” pour en savoir plus.
D’ailleurs on peut faire la même chose avec C# avec NativeAOT
Deux messages plus haut tu défendais que la “gestion de la mémoire” et la “gestion des threads (création, ordonnancement, etc.)” était “forcément dans un langage très bas niveau, comme l’assembleur ou le C”. Or dans Singularity c’est écrit en Sing#.
Le 02/05/2023 à 12h47
Aie aie aie, tu confonds tout. Là, on parle d’un noyau, pas d’un programme. crt0, c’est le code pour démarrer un programme. crt0 n’est pas utilisé dans le cas d’une bibliothèque par exemple.
crt0, c’est lui qui s’assure que la méthode main est appelée, et que les paramètres argc et argv sont correctement initialisés.
Je persiste pour une raison fort simple : cela nécessite d’accéder à des fonctionnalités propre au CPU, abstraction que ne fourni pas le CIL. Tu ne peux pas faire de context switching sans accès au CPU. Tu ne peux pas gérer la pagination, sans avoir accès à certains registres, gérer les interruptions logicielles & matérielles, etc…
Maintenant, si tu enlèves des fonctionnalités au langage pour n’en garder qu’un sous-ensemble (exit la gestion des exceptions, les créations d’objet, le ramasse-miettes, la réflexivité, etc.) alors oui, là tu peux faire des choses. Tu peux écrire des fonctions et les compiler. Mais c’est un peu fort de café que de dire que c’est du C# (ou du Sing#) vu les limitations imposées. Sinon, il est tout aussi juste de dire que le noyau linux est écrit en grande partie en C++.
Le 02/05/2023 à 13h03
En fait, l’espace physique est mappé sur un espace logique. C’est pour ça que tu peux n’avoir que 4Go de RAM, mais avoir des programmes, librairies, driver, etc… chargé à des emplacement mémoire bien au delà des 0x0004000000000000 comme 0x8000000000000000.
C’est parce que tu peux mapper de la mémoire physique sur des plages “virtuelles”.
D’ailleurs, lorsque ce n’est pas le cas, et que tu tentes d’accéder à une zone de la mémoire non mappée, tu as des interruptions comme des PAGE_FAULT
Non. La notion d’allocation/désallocation n’est pas qu’un concept apporté par le langage. Et il y en a bien besoin au niveau noyau. Sinon, linux n’aura absolument pas besoin d’API comme kalloc pour être utilisée au sein même du noyau.
Dans ce cas, désactivons le ramasse-miettes. Mais alors, ce n’est plus du C# ! Le ramasse-miettes fait partie du langage, et il n’y a pas moyen aujourd’hui de le désactiver.
S’amuser à gérer manuellement la mémoire en prenant des adresses arbitraires (aie !!), c’est prendre le risque d’un système instable, car le ramasse-miettes ne saura pas si telle ou telle portion est utilisée ou non. Et s’il a besoin de mémoire (par exemple, pour son fonctionnement interne) ou lors d’une instanciation classique ou à cause d’un boxing, cela risque fortement de créer des conflits.
Le 02/05/2023 à 13h08
Euh, non. MMU, table des pages, TLB, ça te dit quelque chose ?
Je voudrais bien voir un changement de contexte ou un handler d’IRQ en C#… C’est un peu plus qu’un simple accès aux registres. Il faut maîtriser la convention d’appel, la gestion de la pile, etc.
Le 02/05/2023 à 13h21
Oui, mais je pensais que ce n’était des concepts utilisés qu’en user space pour partitionner la mémoire des processus ? C’est peut être là que je me trompe.
Comment est implémenté kalloc? Est-ce qu’il dialogue avec le CPU pour changer l’état des pages d’une manière ou d’une autre, ou est-ce qu’il s’occupe juste d’assigner arbitrairement les plages mémoires pour que les drivers ne s’écrasent pas les uns les autres ? Dans mon raisonnement je pars du principe que c’est la seconde hypothèse.
En d’autres termes, si j’écris un driver s’exécutant en mode kernel et que j’accède à une adresse physique arbitraire, est-ce que ça génère une faute ? Je pensais que non, et c’est peut-être mon erreur.
Dans le pire des cas, il suffit d’allouer un byte array suffisamment large et de l’épingler, et on a ainsi la garantie que la CLR ne va pas utiliser cet espace mémoire par erreur.
Après, encore une fois, je suis le premier à dire que c’est totalement inutile. Je geek juste un peu sur la possibilité technique.
Le 02/05/2023 à 13h36
Oui, tu te trompes. Tu faisais la sieste pendant les cours de système ?
La virtualisation de la mémoire est entièrement pilotée par le noyau, et justement l’espace utilisateur n’a pas le contrôle dessus.
Le 02/05/2023 à 13h38
Bah oui, mais on parle d’écrire un noyau, donc justement la partie qui pilote cette gestion.
Le 02/05/2023 à 13h41
En effet. Et écrire une gestion de la table des pages en C#, ça me fait frisonner rien que d’y penser.
Le 02/05/2023 à 13h47
Raté, c’est la première ;)
Raté encore, ça génère bien une erreur (histoire d’être précis jusqu’au bout, parce qu’un noyau linux peut être utilisé sur tellement d’architecture différente, c’est le cas pour les architectures x86, x86-64, et beaucoup d’ARM. Bref, tout ce qui peut faire tourner un OS bureau ou serveur)
Et cet espace, comment est-il alloué par le CLR ?
Le 02/05/2023 à 14h42
Dire que des mecs ont pondu 4000 lignes de code C dans vmalloc.c pour gérer les pages mémoire, alors que @fdorin fait ca simplement en appelant les fonctions du CPU.
Le 02/05/2023 à 14h43
Mon postulat de base était donc erroné, merci pour la clarification. J’irai me documenter un peu sur le sujet quand j’aurai le temps
Bon point. Sur les projets comme https://codevision.medium.com/running-c-snake-inside-uefi-df193b6213e2 je partais du principe que l’auteur s’abstenait juste d’allouer sur la heap, mais vu que le GC va aussi allouer ses segments initiaux je réalise que le flag true doit entièrement virer le GC.
Le 02/05/2023 à 15h34
Reprend ce que dis KooKiz avant de te montrer condescendant.
C’est d’une manière ou d’une autre. Et non sa seconde hypothèse. Maintenant, je n’ai jamais dis que c’était simple et qu’il suffisait de changer un flag au CPU.
Bonne soirée à toi.
Le 02/05/2023 à 16h41
NGEN.exe est fournit avec C# au moins depuis le 2.0 et permet de compiler en natif. Rien n’empêche d’avoir un bytecode et de le compiler en natif localement un fois à l’install.
Je crois que les surcouches syntaxiques on les a eu (plus dans C++ que C, mais elles sont là).
On au aussi eu d’autres langages, mais aucun n’a percé (trop boîte noire j’imagine, le C étant proche de l’assembleur dans les possibilités offertes)
Le 02/05/2023 à 16h57
En fait, C# permet depuis le début de gérer la mémoire unsafe et de forcer la désallocation (de différentes manières: soit tu joues avec l’API d’allocation mémoire - ou les APIs, soit tu gères précisément via Dispose()), pas besoin d’attendre le ramasse-miette forcément pour libérer des ressources systèmes.
Pour les opérations bas niveau/manipulation des registres: on peut faire un micro kernel avec un HAL - mine de rien c’est un peu ce qu’on fait avec l’IA: on charge des modèles dans des KPU/NPU, mais le code machine du NPU/KPU on ne le connaît pas. Un peu comme si on cpiliait un firmware en le chargeant.
Et pourtant… Sous des systèmes comme OpenVMS, tu peux même lancer une appli lorsqu’un interruption survient (certainement un héritage du PDP11…pour optimiser on peut précharger l’image en RAM avant que l’interruption ne survienne). Ca se configure en script. Donc ça peut exister
En plus des instructions pour RETPOTLINE (support semi-matériel pour SPECTRE), tu as par exemple:
Plusieurs de ces solutions ont un impact plus ou moins visible sur les perfs…
Le 02/05/2023 à 17h09
C’est une erreur de croire ça. La mémoire est gérée et le développeur n’a pas la main dessus. Dispose, les “destructeurs”, etc… c’est bon pour libérer les ressources autre que la mémoire, mais la mémoire, tu n’as pas la main dessus. Jamais.
J’avais écrit il y a quelques années des articles au sujet du ramasse-miettes .Net sur developpez.com (partie 1, partie 2) si tu souhaites approfondir ;)
Quant à la gestion de la mémoire unsafe, il s’agit :
Mais tu ne peux pas lui dire : alloues moi 18 octets, je fais ma tambouille, puis libère ces 18 octets. C’est impossible.
Le 02/05/2023 à 17h54
Et merci pour les articles, je les ai montrés à des collègues à leur sortie!!
Le 02/05/2023 à 17h22
Toujours pas.
Tu trouveras sur wikipedia un joli schéma explicatif des couches du noyau linux:
La gestion mémoire c’est la colonne verte.
Dans cette colonne, la seule couche en lien avec le MMU hardware c’est le bloc “physical memory operations” (en bas du schéma).
Le code qui correspond à ce bloc pour le x64 c’est:
Et dans ce code, nul appel mystérieux pour changer l’état des pages.
Pour la bonne raison que c’est fait par le code C dans les fichiers:
Bonne soirée également.
Le 02/05/2023 à 17h48
Sauf à jouer avec VirtualAlloc, VirtualFree et autres appels “à la main”.
Le 02/05/2023 à 18h46
Mais tu cherches à démontrer quoi exactement ? Tu donnes une collection de liens, mais dans quel but ?
La gestion de l’allocation de la mémoire, c’est un truc complexe qui mélange pas mal d’algorithmie (gestion des pages, mapping, etc.) et de la configuration du MMU.
La question de KooKiz à laquelle je répond est la suivante :
Sachant que sur les architectures “classiques”, le MMU est intégré au CPU. Donc ok, c’est un léger abus de langage de dire que l’on dialogue avec CPU au lieu de dire MMU, mais ça ne change rien à la réponse que j’ai faite.
On peut même aller plus loin en disant qu’une partie du dialogue est faite directement à partir de la RAM. Mais il faut configurer des registres (le CR3 de mémoire) ainsi que des TSS.
Le 02/05/2023 à 18h48
Ah mais dans ce cas, c’est de la mémoire non managée, c’est totalement différent ;)
Le 02/05/2023 à 21h18
Bah ce n’est pas du temps perdu si cela répond à un besoin.
Le 03/05/2023 à 08h12
Répondre correctement à la question posée par KooKiz, en donnant des liens qui lui permettent de corroborer (ou pas) mon assertion.
Bref, le principe d’une démarche scientifique.
Et pas pas un simple argument d’autorité de quelqu’un qui répondrait juste “oui” ou “non”
Le 03/05/2023 à 09h17
D’accord. Là où j’ai choisi la pédagogie, tu as choisi de noyer la personne sous les détails techniques qui nécessitent des heures de lecture pour un dev averti. Chacun son choix
Sinon, tu peux donner aussi la doc d’intel (https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html) bien touffue et sacrément indigeste (pour l’avoir lu il y a de nombreuses années).
Ah non, c’est pas ça un argument d’autorité. Va falloir revoir la définition ;) J’aurais été Linus Torvalds, je dis pas, mais c’est pas le cas
J’ai répondu sans vraiment étayer (pour privilégier la pédagogie), mais je n’ai pas usé de l’argument d’autorité ;)
Le 03/05/2023 à 14h26
Pendant ce temps, à Vera Cruz … je compile / installe GCC 13.1 :)