← Blog

· 25 min de lecture #rust#mqtt#iot#unikernel#arm64#open source#security

urMQTT sur un vrai VPS ARM64 : pas d'écran, pas de générateur matériel de nombres aléatoires, et un handshake trop lent

Ce qui s'est passé après le texte sur v0.3.0 : le premier essai sur un vrai serveur aarch64 KVM (installation sur son disque, une coupure de courant, chiffres du disque), une entrée Diagnostic qui rend compte par le réseau parce que la console est invisible, ce qu'elle a trouvé sur le générateur de nombres aléatoires, un assembleur P-256 pour ARM64 qui a rendu les handshakes complets environ 1,5 fois plus fréquents, et les erreurs que nous avons faites en chemin.

Le texte précédent, urMQTT v0.3.0, se terminait par quatre points sous « La suite » : une décision sur le broker de démonstration public (D1), le fuzzing des analyseurs PCI et virtio avec un test pour les tables de pages verrouillées, une boîte de dialogue pour la clé sur la page du constructeur, et le bare metal. Aucun des quatre n'a été fait dans ce tour, et nous le disons d'abord. Nous avons fait à la place ce qui manquait depuis le début : nous avons fait tourner urMQTT sur un vrai serveur ARM64 sous KVM, et presque tout ce qui suit vient de cette unique machine. Le premier point de l'ancienne liste, la CI, a été nettoyé (le texte précédent et les notes de version qui la disaient rouge ont été corrigés)

La remarque préalable reste la même : le projet est en pré-alpha, les chiffres mesurent du code, des tests et des expériences précises sur une seule machine, pas la maturité en production. Lorsqu'un chiffre n'a pas été mesuré sur la machine cible, c'est indiqué.

Comment cela s'est déroulé dans le temps

Depuis le dernier texte (3 novembre, 02:43) jusqu'à aujourd'hui (4 novembre, 03:18), main compte 29 nouveaux commits, 244 au total. Comme avant, le projet est construit avec Claude Code (les commits portent Co-Authored-By: Claude). Les chiffres sont calculés avec la méthode des deux derniers textes (tous les fichiers .rs hors de vendor/ et fuzz/, les fonctions #[test], les titres ## ADR- dans docs/DECISIONS.md) ; sur l'ancien commit, la méthode donne les mêmes chiffres qu'alors.

Moment Commit Heure Lignes de Rust Tests ADR Commits
dernier texte f1a7fbc 3 nov., 02:43 115 148 962 133 215
aujourd'hui efddf6e 4 nov., 03:18 117 084 978 134 244

Croissance : +1 936 lignes, +16 tests, +1 ADR. À nouveau peu de code nouveau ; l'assembleur P-256 lui-même (1 509 lignes) est intégré tel quel (vendored) et ne compte pas dans le nombre de lignes.

Une deuxième vraie machine

Jusqu'ici, le projet avait un seul vrai serveur : un VPS Contabo avec un AMD EPYC (x86_64, KVM), utilisé pour la comparaison de performances avec Mosquitto. L'ARM64 n'avait tourné que dans QEMU, avec accélération matérielle sur un Mac et sans elle dans la CI. La nouvelle machine est un netcup VPS 500 ARM G12.5 : un cœur Neoverse N1 à environ 3 GHz, 2 vCPU, 3,9 Gio de RAM, un disque virtio de 64 Gio, QEMU/KVM avec firmware UEFI, une carte réseau virtio. Tout a été piloté par l'API REST du fournisseur avec un client en ligne de commande : nous envoyons l'ISO, la branchons comme CD virtuel, changeons le périphérique de démarrage, et éteignons puis rallumons la machine.

Ce que nous y avons fait, dans l'ordre :

  1. D'abord un instantané du système d'origine. Un instantané à chaud n'est pas possible avec UEFI, donc le serveur a été éteint et un instantané hors ligne a été pris.
  2. Installation. L'installateur de l'ISO a écrit l'image sur le disque (compte à rebours de 30 secondes compris, environ 40 secondes en tout) et a éteint la machine lui-même, comme prévu.
  3. Le démarrage depuis le disque installé a pris environ 35 secondes jusqu'à un handshake TLS.
  4. Un message retenu (retained) a survécu à une coupure de courant brutale. Nous l'avons publié, coupé l'alimentation par l'API, redémarré et relu.
  5. Le disque installé, mesuré par l'entrée Diagnostic (lecture seule ; le test d'écriture a été sauté parce que la disposition installée ne laisse pas d'espace non alloué, ce qui est voulu) : lecture séquentielle 332 Mio/s, lectures aléatoires de 4 Kio 22 147 par seconde avec p50 10,4 µs, p90 28,3 µs, p99 671 µs, maximum 9,9 ms (2 000 lectures).

Cinq points ne font pas une suite de tests : c'est une machine, un essai de chaque, et le chemin d'installation a été parcouru une fois sur le vrai disque. Ce que cela montre, c'est que le pilote virtio-blk du noyau, l'installateur et le démarrage fonctionnent sur un vrai invité cloud, et pas seulement dans un émulateur de laboratoire.

Pas d'écran, donc le diagnostic passe par le réseau

L'entrée Diagnostic de v0.3.0 dessine ses chiffres sur le framebuffer. Sur ce serveur, la console du fournisseur affiche « Display output is not active » : la machine virtuelle a une carte graphique virtio pour laquelle nous n'avons pas de pilote, et le port série n'est pas exposé. Les chiffres existaient et personne ne pouvait les lire.

La solution est un mot de démarrage, diag-serve : la machine exécute les mêmes mesures, puis démarre comme un broker live normal et publie le rapport sous forme d'un document JSON dans le message retenu $SYS/diag/report, que seul un certificat d'opérateur peut lire. Un petit outil, urmqtt-diag-png, dessine le tableau de bord à partir de ce JSON avec le même code que le noyau utilise à l'écran (la même disposition et la même police 8x8), de sorte que l'image est l'écran que la machine aurait affiché :

L'écran Diagnostic du VPS ARM64 netcup, dessiné à partir du rapport que la machine a publié par MQTT
L'écran Diagnostic du VPS ARM64 netcup, dessiné à partir du rapport que la machine a publié par MQTT

Deux choses ont été ajoutées à l'écran en chemin, parce qu'elles nous manquaient : la fréquence du CPU (le compteur de cycles du PMU face à la base de temps : 2,95 à 2,98 GHz ici ; là où seul un minuteur à fréquence fixe est lisible, l'écran affiche « not measurable » au lieu de présenter la fréquence du minuteur comme celle du CPU) et un panneau pour le générateur de nombres aléatoires.

De quoi est fait le générateur de nombres aléatoires

Le panneau indique d'où le générateur a été initialisé (seeded) et teste des octets frais de chaque source matérielle. Sur cette machine, il dit :

  • virtio-rng : pas de périphérique. RNDR (l'instruction propre du CPU) : non disponible sur ce CPU.
  • Le générateur de nombres aléatoires EFI du chargeur : 8 valeurs sur 8 non nulles.
  • Le repli sur la gigue de timing du CPU (ADR-038) : 1 024 échantillons de 64 pas via le compteur de cycles du PMU, 3 bits par échantillon estimés, 768 bits crédités (un quart de l'estimation, voulu), tests de santé réussis.
  • La sortie du générateur, un test de plausibilité sur 4 096 octets : 49,6 % de uns, la plus longue série de 16 bits. C'est une vérification que rien n'est bloqué ni biaisé, pas une certification statistique.

Le générateur de ce serveur repose donc sur le repli par la gigue et sur ce que le firmware a transmis. C'est exactement ce que décrit l'ADR-038, et c'est l'initialisation la plus faible que le noyau accepte. Nous ne le disons pas cassé : les bits crédités sont au-dessus du seuil que le noyau exige (256), et l'estimateur est prudent. Nous ne pouvons pas non plus prouver qu'il vaut une source matérielle. Savoir si une image de production doit refuser de démarrer sans source matérielle, sauf si l'opérateur l'autorise explicitement, est une question ouverte pour le propriétaire du projet (elle figure dans la feuille de route, plus bas). En pratique, c'est aussi une question pour le fournisseur : un périphérique matériel de nombres aléatoires pour la machine virtuelle la trancherait.

Un handshake trop lent

L'entrée Diagnostic a aussi montré ce que coûte un handshake TLS mutuel complet sur le serveur : 1,08 ms. Presque tout est de l'arithmétique à clé publique : deux vérifications ECDSA P-256 (le certificat du client et la preuve du client), environ 508 µs chacune, X25519 176 µs, une signature ECDSA 141 µs. Sur x86_64, nous avions résolu cela plus tôt (ADR-130, l'assembleur OpenSSL/Intel : P-256 trois à quatre fois plus rapide) ; sur ARM64, c'était encore le code portable de RustCrypto qui tournait.

Nous avons fait la même chose pour ARM64 (ADR-255). L'assembleur est le nistz256 ARMv8 d'OpenSSL (Apache-2.0), repris de ring 0.17.14 et intégré avec sa provenance et chaque modification mécanique consignées. Ce qui a compté dans les détails :

  • Uniquement des entiers. L'assembleur n'utilise aucun registre NEON. Les deux fonctions de sélection dans la table que l'original écrit avec NEON, nous les avons abandonnées pour écrire en Rust des balayages masqués à temps constant (ils coûtent au plus 1,4 µs sur une signature de 12 µs).
  • Protection des branchements. Le noyau est compilé avec BTI et l'authentification de pointeurs. Chacun des 8 points d'entrée exportés a un landing pad, vérifié dans le désassemblage du noyau, et les six qui sauvegardent le registre de lien le signent.
  • Des tests, parce que c'est de la cryptographie dans la base de confiance. Toute la suite x86_64 tourne maintenant aussi sur aarch64 Linux : arithmétique de corps et de scalaires face à une référence « scolaire », toute la table du générateur (2 368 entrées) face à RustCrypto, des signatures égales bit à bit à celles de RustCrypto, les verdicts de vérification, ECDH avec des entrées hors courbe et nulles, et les tests à réponse connue qui tournent à chaque démarrage par les chemins de production. Dans une machine virtuelle à quatre cœurs sous une tempête d'interruptions, 59 526 tours de tests à réponse connue ont tourné avec 0 divergence.
  • Un test de timing avec témoin, et un signal qui était notre propre test. Une multiplication volontairement fuyante obtient |t| de 482 à 1 755, donc le test voit une fuite à cette échelle. Sur un cœur Apple dans un conteneur, ECDH a obtenu 0,2 à 2,1, la signature 0,5 à 1,9, la génération de clé 0,8 à 5,5. Sur le cœur serveur arm64 du runner de CI, la signature ECDSA a obtenu |t| = 8,6, 9,1 et 8,3 en trois essais, au-dessus de notre borne de 7, alors qu'ECDH (3,9) et la génération de clé (1,9) ont passé sur la même machine. Un résultat qui se répète n'est pas du bruit, nous l'avons donc consigné comme constat ouvert (A255-W1) et, pendant quelques heures, relevé à 12 la borne de ce seul cas pour que le build puisse passer. Puis nous avons trouvé la cause, et c'était le banc de test : le cas signait un seul message fixe, de sorte que la clé creuse produisait la même signature à chaque fois et les clés aléatoires une différente à chaque fois, et l'encodage DER d'une signature répétée est plus rapide (|t| = 49 à 57 pour l'encodage seul). Avec un message aléatoire par mesure dans les deux classes, le cas obtient 1,4 et 1,8 sur le runner (une machine virtuelle Neoverse N2), la seule génération du nonce 2,7 et 1,1, et la borne est de retour à 7. Une chose reste ouverte (A255-W2) : le drapeau du processeur qui rend le timing du multiplieur indépendant des données sur les cœurs Arm (DIT) n'est positionné nulle part, ni par le noyau ni autour des appels côté hôte. Aucune mesure ne montre de différence, mais la machine virtuelle du runner n'expose pas cette fonction, donc le test ne pouvait pas non plus en montrer.

Ce que cela a apporté

D'abord le microbenchmark sur la machine où nous avons développé, un Apple M4 Pro (pas le CPU cible, donc les rapports sur le serveur peuvent différer), le même code que le handshake appelle, avant et après :

Opération avant (µs) après (µs) rapport
génération de clé 30,8 7,0 4,4x
ECDH P-256 135,2 25,0 5,4x
signature ECDSA 34,7 11,6 3,0x
vérification ECDSA (clé inconnue) 147,4 29,1 5,1x
vérification CA (émetteur enregistré) 54,2 9,6 5,6x
X25519 (code inchangé) 20,4 20,1 1,0x
estimation du handshake (somme de ce qui précède) 292 104 2,8x

Ensuite la réalité : le même générateur de charge, la même méthode que dans le texte précédent sur les performances (handshake TLS 1.3 complet avec certificat client, sans reprise de session, MQTT CONNECT, le serveur ferme en premier), lancé depuis une machine à 9 ms du serveur, contre le même VPS netcup, avant et après le changement. L'image de benchmark a des limites de handshake relâchées, comme dans la comparaison x86_64 ; trois répétitions, le chiffre est la médiane.

Threads avant (connexions/s) après (connexions/s) rapport erreurs
32 848 (408-855) 1 317 (957-1 317) 1,55x 0
64 827 (815-839) 1 398 (1 352-1 416) 1,69x 0
128 778 (714-788) 1 316 (1 313-1 383) 1,69x 0
Part TLS d'une connexion, p50, 32 threads 18,5 ms 13 ms

Les handshakes complets par seconde ont augmenté d'environ 1,55 à 1,7 fois, et non des trois fois que donnerait l'arithmétique seule. La raison est simple et mérite d'être dite : nous avons accéléré P-256, alors que X25519 (176 µs), la pile TCP/IP, la couche d'enregistrements et MQTT sont inchangés, si bien que la fraction restante gagne en importance (loi d'Amdahl). Le prochain candidat est X25519.

Pour s'orienter à côté du serveur x86_64 du texte précédent. Ce n'est pas comparable comme une course : des CPU différents, un nombre de cœurs différent (4 contre 2), une distance différente au générateur (15 ms contre 9 ms) et, dans les deux cas, un hôte de charge partagé qui a perdu 5 à 60 % de son propre CPU pendant les essais. La colonne comparable est le coût CPU du serveur par handshake :

Contabo, x86_64 EPYC (asm) netcup, ARM64 N1 avant netcup, ARM64 N1 après
CPU du serveur par handshake 0,26 ms (la console du broker) 1,08 ms (Diagnostic) 0,55 ms (Diagnostic, un essai, voir ci-dessous)
handshakes/s, 32 threads 169 (bench) 848 1 317
handshakes/s, 64 threads 278 (bench) 827 1 398
handshakes/s, 128 threads 413 (bench) 778 1 316

Le même jour, l'entrée Diagnostic a tourné de nouveau sur cette machine, avec l'assembleur (dans un build qui contient aussi le pilote graphique décrit dans la mise à jour à la fin) : le coût CPU du serveur pour un handshake TLS mutuel a été de 553 µs contre 1,08 ms avant, soit 1,95 fois moins. La vérification ECDSA a pris 192 µs (508 µs avant), la signature 78 µs (141 µs), et X25519 209 µs (176 µs ; ce code est inchangé, et la fréquence du CPU de cet essai était de 2,58 GHz contre 2,95 à 2,98 GHz dans les précédents, si bien que les chiffres isolés sur cette machine partagée bougent de plusieurs dizaines de pour cent). C'est un seul essai, sur un hôte partagé. Que le débit de handshakes ait été multiplié par 1,55 à 1,7 alors que le coût propre du serveur par handshake était divisé par 1,95 est cohérent : le reste d'une connexion, c'est la pile, le générateur et le réseau. Le bruit d'un essai à l'autre se voit dans les fichiers bruts : chaque série de trois a une valeur aberrante (408 avant et 957 après à 32 threads), quand l'hôte de charge a perdu l'essentiel de son CPU au profit d'autres machines virtuelles. À 128 threads, c'est le générateur, et non le serveur, qui est à sa limite sur les deux machines.

Le reste de la suite sur cette machine

La même suite que pour le serveur x86_64 (débit, latence, fan-out, connexions inactives) a tourné en entier contre la nouvelle version. Il n'y a pas de « avant » pour ces lignes : l'essai a été arrêté pour construire l'assembleur, ce sont donc les états après le changement, et l'assembleur ne touche pas ces chemins, sauf les handshakes qui ouvrent les connexions. Un fait explique l'essentiel de ce qui suit : cette machine virtuelle a deux vCPU. Le cœur 0 fait la carte réseau, la répartition et tout le travail MQTT et TLS, le cœur 1 est le cœur de la base de données et était occupé à 2 à 3 % tout du long. Le serveur x86_64 avait quatre vCPU et deux cœurs de travail. Tout ce qui suit est donc la performance du broker sur un seul cœur.

Connexions inactives 5 000 10 000 20 000
connectées 5 000 sur 5 000 en 4,3 s 10 000 en 9,3 s 20 000 en 21,2 s
croissance du tas du noyau par connexion 0,34 Ko 0,41 Ko 0,43 Ko
erreurs 0 0 0

(0,50 à 0,66 Ko par connexion sur le serveur x86_64 au commit H7. Le chiffre du tas est $SYS/broker/memory/used moins sa valeur avant la première connexion.)

Latence à débit modéré (8 paires x 100 messages/s, 64 o) p50 p99
QoS 0 4,0 ms 6,9 ms
QoS 1 4,1 ms 7,0 ms
Fan-out (1 éditeur, 64 o) délivrés par seconde p50 p99
100 abonnés, QoS 0, 50 msg/s 5 000 (tous) 5,9 ms 8,6 ms
100 abonnés, QoS 1, 50 msg/s 5 000 (tous) 6,3 ms 10,0 ms
1 000 abonnés, QoS 0, 10 msg/s 8 805 sur 10 000 207 ms 5,4 s
Flood, 16 paires, éditeurs aussi vite que le broker accepte publiés/s délivrés/s p50 / p99 connexions perdues
QoS 0, 64 o 231 317 85 140 1,36 s / 2,8 s 0
QoS 0, 1 Kio 62 110 25 506 336 ms / 873 ms 0
QoS 1, 64 o 107 349 55 965 21 ms / 29 ms 0
QoS 1, 1 Kio 51 369 25 054 47 ms / 60 ms 0
QoS 1, 64 o, 64 paires 130 462 69 411 69 ms / 87 ms 0

Comment lire cela. La latence à débit modéré est la contribution du broker plus un trajet jusqu'au générateur : le générateur est plus proche de ce serveur que celui de la comparaison x86_64, donc les deux colonnes de latence ne sont pas comparables. Le flood QoS 0 montre le tableau habituel d'un cœur unique surchargé : le broker accepte 231 000 messages par seconde et en délivre 85 000 (le reste est écarté par les règles de contre-pression, c'est leur rôle) avec des latences de l'ordre de la seconde, et aucune connexion n'a été perdue ; sur le serveur x86_64, le même type de flood coûtait plusieurs connexions par essai au watchdog de 20 ms (l'ADR-221 a depuis changé la manière dont ce budget est compté). La ligne à 1 000 abonnés a le même caractère qu'avant, des queues de l'ordre de la seconde, en partie dues au générateur. Les chiffres au commit H7 sur le serveur x86_64 sont dans le texte précédent ; nous ne les mettons pas dans le même tableau que ceux-ci, parce que le code entre les deux mesures a changé sur le chemin des données (ADR-221 à ADR-224) et que les machines diffèrent en tout.

Erreurs que nous avons trouvées nous-mêmes

  • L'image disait « no disks found » et le disque était dans le rapport. La première version de urmqtt-diag-png ne lisait pas du tout le champ disks. Le propriétaire du projet a regardé l'image, dit qu'elle avait l'air fausse, et il avait raison. Corrigé, et un test relit maintenant un disque à partir du JSON.
  • Nous avons déclaré l'installateur terminé trop tôt. L'état du serveur est passé deux fois à « off » : une fois à la fin du cycle d'alimentation et une fois quand l'installateur a fini. Notre script a pris le premier pour le second, a détaché l'ISO et démarré l'ancien système, qui a alors annoncé l'ancien numéro de version et nous a fait chercher dans l'installateur un défaut qui n'y était pas. Le script attend maintenant d'abord un démarrage tout neuf.
  • L'historique de progression a été perdu. Une analyse pour la feuille de route a montré que le commit de l'étape S6 avait remplacé docs/PROGRESS.md (1 763 lignes, étapes M0 à S5) par sa propre entrée de 26 lignes. Cela est resté inaperçu pendant des jours, bien que le README appelle ce fichier « la source de vérité ». Il a été restauré depuis l'historique.
  • La CI a échoué après l'assembleur, à deux endroits. Trois tests de fumée avaient la taille de l'image de démarrage écrite en dur (« 10 MiB »), qui est passée à 11 MiB avec le noyau plus gros ; ils ne supposent plus la taille. L'autre échec était le test de timing décrit plus haut : la première fois, il ressemblait à du bruit sur un runner partagé, donc nous avons fait répéter le test trois fois ; il a échoué aux trois essais, et c'est ainsi que nous avons compris que c'était un signal, et le signal s'est révélé être notre propre test (il signait le même message à chaque fois). Nous avons relevé cette seule borne pendant quelques heures, nous l'avons dit ouvertement, et nous l'avons abaissée de nouveau une fois la cause corrigée.
  • La documentation compte trois mots de démarrage et le code en a quatre (diag-serve), et le tableau des étapes du README montre encore comme prévu le travail de la semaine dernière. Les deux sont dans la feuille de route comme points à corriger.

Une feuille de route, avec des questions

Il existe pour la première fois une feuille de route : environ 40 points en trois phases (v0.4 durcissement et exploitation ; protocole et réseau ; montée en charge horizontale, plus de clouds et bare metal), chacun avec une raison tirée d'un document, un effort, un risque et une manière de vérifier, 16 questions auxquelles seul le propriétaire peut répondre, et une liste de ce qui est hors périmètre. Elle dit clairement quelques points : seul MQTT 3.1.1 est pris en charge, un publish QoS 2 ferme la connexion, il n'y a pas d'IPv6 (le fournisseur attribue un /64), pas de WebSocket et pas de connexion sortante depuis le broker, et il n'y a pas de pilotes pour les périphériques réseau et de stockage des grands clouds.

Ce qui n'est pas encore prouvé

  • Le coût CPU par handshake avec l'assembleur n'a été mesuré qu'une seule fois sur le cœur Neoverse (553 µs contre 1,08 ms avant, à une fréquence plus basse, sur un hôte partagé) ; le 1,55 à 1,7 fois vient du débit de handshakes complets, et le 3 à 5 fois d'un cœur Apple. Le côté x86_64 du remaniement (le code déplacé dans son propre fichier) a été vérifié au niveau des types et compilé, mais ses tests unitaires n'ont pas été exécutés et le noyau x86_64 n'a pas été démarré après lui : les suites x86_64 ne sont pas dans la CI, elles sont lancées à la main sur le VPS Contabo, et cela n'a pas encore été fait pour ce changement.
  • Le temps constant : pour la génération de clé P-256, ECDH et la signature (la clé et le nonce), le test statistique n'a trouvé aucune dépendance à un secret creux. Il a tourné sur un cœur Apple et sur le runner de CI (une machine virtuelle Neoverse N2), pas sur le cœur Neoverse N1 de netcup, et jamais avec le drapeau DIT positionné sur un cœur serveur (A255-W2, ouvert : le noyau ne le positionne pas). Il n'a pas tourné pour X25519 ni Ed25519. Un test en boîte noire ne borne que ce qu'il peut résoudre à sa taille d'échantillon.
  • Un serveur, un fournisseur, une installation. Plusieurs résultats (installation, une coupure de courant) sont un essai unique. Hors handshakes, les lignes de performance n'ont pas de « avant », et une machine à deux vCPU donne au broker un seul cœur de données.
  • Le générateur de nombres aléatoires de ce serveur est initialisé à partir de la gigue et du firmware, comme décrit plus haut.
  • La clé de signature est toujours une clé de test, les images de la version sont des builds de développement, et les traductions de ce texte ont été écrites par une IA et n'ont pas été relues par des locuteurs natifs.
  • Pas d'audit indépendant, pas de bare metal, pas d'IOMMU.

La suite

  1. X25519 en assembleur pour ARM64 (c'est 176 µs du handshake restant), et la répétition de la mesure par handshake sur le cœur Neoverse, plus d'une fois.
  2. Une décision sur la valeur par défaut du générateur de nombres aléatoires : refuser de démarrer sans source matérielle, sauf indication contraire de l'opérateur, ou garder le repli par la gigue et le dire haut et fort.
  3. L'ancienne liste : une décision sur D1, le fuzzing des analyseurs PCI et virtio, la boîte de dialogue pour la clé sur la page du constructeur.
  4. Depuis la feuille de route, pour la prochaine version : une vraie clé de signature et une PKI de production, MQTT 5.0 et QoS 2.

Le code est sur github.com/zeljan-alduk/urMQTT ; docs/PROGRESS.md reste la source de vérité sur ce qui fonctionne, docs/PERFORMANCE.md sur ce qui a été mesuré (la section 10 contient les chiffres de l'assembleur), docs/AUDIT.md sur ce qui n'est pas prouvé. Pré-alpha, comme avant ; les rapports de bogues et les signalements de sécurité selon les instructions de SECURITY.md sont les bienvenus.

Mise à jour, 4 novembre, plus tard le même jour. Quatre choses des heures qui ont suivi la publication de ce texte.

  1. Le chiffre manquant. L'entrée Diagnostic a tourné de nouveau sur le serveur netcup avec l'assembleur et a donné le nombre qui manque dans le premier tableau : 553 µs de CPU serveur par handshake TLS mutuel contre 1,08 ms avant (détails sous ce tableau).
  2. Le signal de la signature, c'était notre test. La cause du signal de timing décrit plus haut a été trouvée et corrigée dans le banc de test (il signait le même message à chaque fois) ; la borne est de retour à 7. Ce qui reste ouvert, c'est que le drapeau DIT n'est positionné nulle part (A255-W2).
  3. Le problème d'écran est résolu, et il est sur main. Nous avons écrit un pilote pour la carte graphique virtio (2D seulement, ADR-256), activé par une clé de configuration inscrite dans l'image (console.virtio_gpu, off par défaut, auto et on demandent le format de configuration 5). Avec on, l'onglet Screen de la console du fournisseur affiche le tableau de bord Diagnostic en direct sur le serveur netcup, la même image que plus haut, y compris le dernier écran avec « press any key ». Sa cible de fuzzing a trouvé un vrai bogue dans la première version : une réponse d'informations d'affichage plus courte de quatre octets que la spécification était acceptée comme valide (A256-W1) ; un vrai périphérique envoie toujours la réponse entière, donc le serveur n'était pas touché, et l'analyseur rejette désormais la réponse courte. Ce que nous n'avons pas vérifié : que l'écran sombre venait bien du micrologiciel qui réinitialise la carte au moment de passer la main au noyau (probable, non confirmé), l'interaction avec Secure Boot, et x86_64 sur une vraie machine (il n'a tourné que sous émulation). Une limite connue (A256-W2) : le réglage auto ne peut pas distinguer un framebuffer émulé vivant à côté d'une carte virtio d'un framebuffer mort, donc dans cette seule configuration il prend la carte virtio. Le pilote ajoute au noyau un analyseur des réponses de l'hyperviseur, c'est pourquoi il est désactivé sauf si la configuration le demande.

  4. La version. Tout cela est dans v0.4.0, publiée le soir même comme préversion (version GitHub). La page du constructeur de ce site la propose en premier ; elle demande le format de configuration 6, et les anciens modèles (v0.2.0 à v0.3.0) refusent les nouvelles clés avec un message qui dit d'utiliser une version plus récente. Les limites de v0.3.0 restent : la clé de signature est toujours une clé de test, et les images sont des builds de développement avec des certificats de test. La CI sur le commit de la version n'est devenue verte qu'après qu'un job a été relancé (un test client dans un scénario de test de fumée a expiré une fois et a réussi la deuxième fois). Ce que nous avons vérifié sur les fichiers publiés : la signature minisign, les sommes de contrôle, les attestations de build du noyau et du SBOM, et le modèle avec les nouvelles clés (v0.4.0 les accepte, v0.3.0 les refuse). Le pilote des nouveaux périphériques virtio (console, balloon, input, vsock) est dans la version, mais il est désactivé par défaut et n'a pas tourné sur un vrai serveur.

Commentaires

Règles des commentaires

Règles des commentaires

Les commentaires servent à partager expériences et questions sur les sujets du blog. Ces règles gardent la discussion utile pour tous.

  1. Courtoisie Pas d'insultes, de menaces, de harcèlement, de discours de haine ni de discrimination, quel qu'en soit le motif. Critiquez l'argument, pas la personne.
  2. Rester dans le sujet Un commentaire doit porter sur l'article ou sur la discussion qui le suit.
  3. Ni publicité ni spam Pas de publicité, de chaînes de messages ni de liens sans contexte. Les liens et images sont bienvenus quand ils enrichissent la discussion.
  4. Vie privée d'autrui Ne publiez pas de données personnelles d'autres personnes : noms complets de particuliers, adresses, téléphones, e-mails, photos sans consentement.
  5. Droits d'auteur Ne publiez que du contenu que vous avez le droit de partager. En citant, indiquez la source.
  6. Une seule identité Utilisez un seul pseudo et ne vous faites pas passer pour quelqu'un d'autre.
  7. Confirmation par e-mail Un commentaire n'est publié qu'après confirmation du lien envoyé par e-mail. L'adresse n'est pas affichée ni utilisée à d'autres fins ; les commentaires non confirmés sont supprimés après 48 heures.
  8. Modération Les commentaires contraires aux règles sont masqués ou supprimés sans préavis, et une discussion peut être verrouillée. Les décisions des modérateurs sont définitives.
  9. Responsabilité L'auteur est responsable du contenu de son commentaire. Les commentaires ne reflètent pas les positions d'ALDO TECH.
  10. Signalement Signalez tout contenu inapproprié à info@aldo.tech.