- Un bug d’omission de libération de verrou de ressource a été découvert dans le code de l’Apollo Guidance Computer (AGC), considéré depuis 57 ans comme presque parfait
- L’équipe JUXT a analysé 130�0 lignes d’assembleur à l’aide du langage de spécification IA Allium et de Claude, et a identifié une défaillance que les méthodes de vérification classiques n’avaient pas mise en évidence
- Dans le chemin de terminaison anormale (BADEND) de la routine de contrôle des gyroscopes, le verrou
LGYROn’est pas libéré, ce qui peut bloquer ensuite toutes les fonctions liées aux gyroscopes - Si, pendant la mission réelle, l’interrupteur Cage avait été actionné par erreur en orbite lunaire, l’alignement Program 52 aurait pu être interrompu et Collins aurait pu le prendre pour une panne matérielle
- Ce cas montre que l’analyse fondée sur des spécifications comportementales est une méthode puissante pour découvrir de nouveaux défauts, même dans du code ancien
Un défaut potentiel découvert dans l’ordinateur de guidage d’Apollo 11
- L’Apollo Guidance Computer (AGC) est l’une des bases de code les plus minutieusement examinées de l’histoire, analysée par d’innombrables développeurs et chercheurs
- Pourtant, un bug de verrouillage de ressource non libéré passé inaperçu pendant 57 ans a été confirmé dans le code de contrôle des gyroscopes
- Sur un chemin d’erreur, le verrou n’est pas libéré, ce qui peut désactiver la fonction de réalignement de la plateforme de guidage
- L’équipe JUXT a utilisé le langage de spécification fondé sur l’IA Allium et Claude pour transformer 130�0 lignes d’assembleur AGC en 1200 lignes de spécifications comportementales
- Les spécifications ont été extraites directement du code afin de modéliser tous les chemins d’acquisition et de libération des ressources
- Ce processus a mis au jour un défaut qui n’apparaissait pas avec la simple lecture du code ni avec l’émulation
Structure du code et approche d’analyse
- Le code source de l’AGC a été rendu public en 2003, lorsque Ron Burkey et des bénévoles ont retranscrit manuellement les imprimés du MIT Instrumentation Laboratory
- En 2016, le dépôt GitHub de Chris Garry a été publié, permettant à des développeurs du monde entier d’examiner ce code assembleur pour 2 KB de RAM et un CPU à 1 MHz
- Le programme était stocké dans 74 KB de core rope memory, où des fils de cuivre étaient tissés à la main à travers des tores magnétiques pour représenter les 1 et les 0
- Les techniciennes qui effectuaient ce travail étaient surnommées « Little Old Ladies », et cette mémoire était appelée LOL memory
- Jusqu’ici, il n’existait aucun historique de vérification formelle, model checking ou analyse statique appliqué à l’AGC
- L’essentiel de la vérification s’était concentré sur la lecture du code, l’émulation et la validation de la fidélité de la transcription
- JUXT a rédigé en Allium une spécification comportementale du sous-système IMU (Inertial Measurement Unit)
- En modélisant le moment d’acquisition et de libération de chaque ressource partagée, l’équipe a pu identifier le défaut
Omission de libération du verrou dans la routine de contrôle des gyroscopes
- L’AGC gère l’IMU à l’aide d’un verrou partagé nommé
LGYRO- Lorsqu’il applique un couple aux gyroscopes, il acquiert ce verrou, puis le libère une fois les trois axes terminés
- Cela empêche que deux routines manipulent le matériel en même temps
- Cependant, dans le chemin de terminaison anormale, le verrou n’est pas libéré
- En cas de terminaison normale, la routine
STRTGYR2libèreLGYRO, mais si un « Caging » (verrouillage physique de protection du gyroscope) se produit, l’exécution bifurque vers la routineBADEND - Dans
BADEND, il manque les deux instructionsCAF ZEROetTS LGYRO(4 octets au total), ce qui laisse le verrou actif
- En cas de terminaison normale, la routine
- Si
LGYROn’est pas libéré, toutes les routines ultérieures de couple gyroscopique se bloquent en attente du verrou- L’alignement fin, la correction de dérive, le couple manuel et toutes les autres fonctions liées aux gyroscopes s’arrêtent alors
Impact potentiel derrière la Lune
- Le 21 juillet 1969, Michael Collins exécutait périodiquement Program 52 (programme d’alignement par observation d’étoiles) en orbite lunaire
- Si la plateforme dérivait, l’orientation du moteur de retour risquait d’être incorrecte
- Si, pendant une opération de couple, l’interrupteur Cage avait été actionné par erreur, forçant le passage dans le chemin
BADEND,LGYROaurait pu ne jamais être libéré et tous les P52 suivants auraient pu se bloquer- Le DSKY (affichage-clavier) aurait accepté les entrées sans réagir
- Comme les autres fonctions continuaient à fonctionner normalement, Collins aurait pu l’interpréter comme une panne matérielle
- Un redémarrage (hard reset) aurait résolu le problème, mais après l’expérience de l’alarme 1202 durant l’alunissage, il aurait été difficile de décider immédiatement d’un reset
Conception défensive du système et ses limites
- L’équipe du MIT dirigée par Margaret Hamilton a introduit des concepts fondateurs du génie logiciel moderne, comme l’ordonnancement par priorité, le multitâche asynchrone et la protection au redémarrage
- C’est grâce à cette conception que l’alunissage a pu se poursuivre malgré les alarmes 1202
- La plupart des défauts majeurs relevaient d’erreurs de spécification et, comme l’a documenté Don Eyles, l’absence de synchronisation de phase entre matériels avait déjà entraîné une hausse de charge CPU
- Ce défaut suit une structure comparable
BADENDest une routine de fin générale pour les changements de mode de l’IMU ; elle libère des ressources communes commeMODECADR, mais ne traite pasLGYRO- Comme la logique de redémarrage réinitialise
LGYRO, le système récupérait correctement pendant les tests, ce qui a masqué le défaut
- En revanche, dans une situation réelle sans redémarrage, le gyroscope aurait pu rester bloqué de façon permanente
Comment le défaut a été découvert avec Allium
- Les spécifications Allium modélisent le cycle de vie (lifecycle) de chaque ressource
- Le champ
gyros_busyreprésenteLGYRO, la règleGyroTorquedéfinit l’acquisition du verrou, et la règleGyroTorqueBusydéfinit l’attente lorsque le verrou est déjà pris
- Le champ
- La spécification exprime l’obligation suivante : « si le verrou passe à true, il doit obligatoirement revenir à false »
- En retraçant tous les chemins, Claude a constaté que la libération a bien lieu sur le chemin normal (
STRTGYR2), mais manque sur le chemin d’erreur (BADEND)
- En retraçant tous les chemins, Claude a constaté que la libération a bien lieu sur le chemin normal (
- L’approche fondée sur les spécifications vérifie non pas ce que le code fait, mais ce qu’il devrait faire
- Les tests confirment le comportement actuel du code, tandis que les spécifications valident le comportement intentionnel
- Les spécifications Allium et le code de reproduction du bug ont été publiés sur GitHub
Implications modernes et enseignements
- À l’époque, les programmeurs devaient libérer manuellement les verrous à l’aide des instructions
CAF ZEROetTS LGYRO- Ils devaient mémoriser tous les chemins d’exécution et y insérer eux-mêmes le code de libération
- Les langages modernes préviennent structurellement ce type de problème de fuite de ressource
- Le
deferde Go, letry-with-resourcesde Java, lewithde Python ou le système de propriété de Rust garantissent une libération automatique
- Le
- Malgré cela, les défauts de type CWE-772 (Missing Release of Resource after Effective Lifetime) existent toujours
- Connexions à des bases de données, verrous distribués, descripteurs de fichiers, ordre d’arrêt d’infrastructures : autant de cas qui restent à la charge des programmeurs
- Toutes les missions Apollo sont revenues avec succès, mais ce défaut a ensuite été recopié tel quel dans les logiciels COMANCHE (module de commande) et LUMINARY (module lunaire), sans être corrigé
- Ce défaut resté caché pendant 57 ans illustre l’importance de l’analyse fondée sur des spécifications comportementales
1 commentaires
Commentaires sur Hacker News
Je suis Mike Stewart, j’ai dirigé le projet de restauration de l’AGC sur la chaîne CuriousMarc et je suis co-administrateur de VirtualAGC
Le bug mentionné cette fois-ci était bien un défaut réel du logiciel AGC. Mais il n’est pas resté en l’état pendant toute la durée du programme. Il a été découvert pendant les tests de phase 3 de SATANCHE, consigné sous la référence L-1D-02, puis corrigé entre Apollo 14 et 15
Les rapports correspondants sont consultables dans ibiblio document 1 et document 2
La correction n’a pas consisté simplement à ajouter deux lignes pour remettre LGYRO à 0, elle incluait aussi une réorganisation de la structure du code et une logique pour réveiller les tâches en attente. En comparant le code d’Apollo 14 et d’Apollo 15 (code Apollo 14, code Apollo 15), on peut voir la différence
Ce n’est pas un bug qui se produit silencieusement comme l’article le décrit. LGYRO est aussi initialisé dans STARTSB2, qui s’exécute à chaque changement de programme et résout automatiquement le problème. En pratique, cela ne se produisait donc que rarement, uniquement lors d’une manœuvre de couple pendant BADEND
Si le bug persiste, plusieurs tâches s’accumulent et finissent par provoquer une erreur 31202, la version ultérieure du 1202. Le problème a été identifié avant le vol d’Apollo 14 et une procédure de récupération a été ajoutée dans les Apollo 14 Program Notes
Par ailleurs, même si Ken Shirriff est crédité pour l’analyse au niveau des portes logiques, c’est en réalité moi qui en ai fait la plus grande partie
Virtual AGC n’a pu vérifier la correspondance octet par octet avec les dumps originaux de core rope que pour certains programmes, pas pour l’ensemble. La majeure partie des sources a été restaurée à partir d’imprimés ou de checksums
Margaret Hamilton était la « rope mother » de Comanche, le logiciel du module de commande, tandis que Luminary, le module lunaire, relevait de Jim Kernan. On peut le vérifier dans l’organigramme de 1969
Au moment de l’alarme 1202, l’AGC n’avait pas été conçu pour supprimer les tâches de faible priorité. En réalité, le guidage d’atterrissage était la tâche de plus faible priorité, alors que le contrôle d’antenne ou la mise à jour de l’affichage avaient une priorité supérieure. Ce document récapitule les priorités des différentes tâches
Enfin, des tests sur le matériel réel ont confirmé que la cause de l’alarme 1202 n’était pas un décalage de phase, mais une différence de tension (28V vs 15V). Une vidéo de l’expérience est disponible via ce lien YouTube
Si l’Apollo AGC vous intéresse, je recommande vivement la chaîne YouTube CuriousMarc. Une équipe techniquement brillante y documente la restauration et l’analyse de plusieurs composants de l’AGC
Le point le plus fascinant est sans doute la réinterprétation de la fameuse alarme 1202. On la présente généralement comme une simple erreur capteur sans conséquence, alors qu’elle aurait en réalité pu être très grave dans certaines conditions
Mon extrait de code préféré est celui-ci
Lien GitHub
cadrde LispJe me demande si quelqu’un a vérifié que ce bug existe vraiment. L’IA est forte pour ce type d’analyse exploratoire, mais elle a encore un taux de faux positifs élevé
Selon le contexte, cela peut être important… ou non. Et il y a aussi beaucoup de bugs que l’IA ne détecte pas
Je n’ai pas l’expertise pour le vérifier moi-même, mais je trouve ça très intéressant
Cela dit, l’explication de la prise de verrou et du scénario d’échec était assez convaincante
Le fait qu’ils aient trouvé un vrai bug est intéressant. Mais la mise en scène dramatique du texte relève presque de la fiction
Par exemple avec l’idée d’actionner un interrupteur avec le coude, ou d’exagérer un problème qu’un reset permettrait de résoudre. Cela rend le texte plus sensationnaliste, mais moins crédible. En plus, le style fait penser à un texte écrit par une IA, ce qui est agaçant
Mais pour expliquer un bug subtil à un lectorat généraliste, il faut un minimum de storytelling. Si c’est trop technique, les gens décrochent ; si c’est trop dramatique, les experts critiquent. Je pense que trouver cet équilibre est difficile
J’ai exécuté moi-même le code de reproduction (repro) inclus dans l’article
Lien GitHub
Ça s’exécute, mais la phase 5 (démonstration du deadlock) est une sortie entièrement factice. Elle n’exécute pas réellement l’émulateur et affiche seulement un résultat attendu
J’ai donc soumis ma propre PR, pour corriger cela afin que ça fonctionne vraiment dans l’émulateur, et j’ai aussi vérifié que le patch de deux lignes résout bien le bug
Le code généré par IA a tendance à s’arrêter en proclamant « c’est parfait maintenant ! », et des gens y croient puis le déploient tel quel. C’est ça, le vrai problème
L’article lui-même est intéressant, mais il dégage une impression artificielle, comme s’il avait été écrit par un LLM
Le fait qu’un logiciel qui a envoyé des humains sur la Lune avec seulement 4 KB de mémoire puisse encore contenir des bugs non découverts montre bien que même un petit code peut cacher une vraie complexité
Dire qu’ils ont « dérivé une spécification à partir du code » est inexact. Il faudrait revoir ce que signifie vraiment le terme specification
L’article comme le dépôt sont des résultats bâclés (sloppy)
Quand on regarde le dépôt, la prétendue « reproduction » n’exécute pas réellement le bug et se contente d’aligner des instructions d’affichage disant « voilà ce qui se passerait »