• [^] # Re: Attaque par le compilateur

    Posté par . En réponse au journal Bootstrap Binary seed. Évalué à 6.

    Sommaire

    Et descend de ton piédestal tu vas prendre froid.

    Je viens de voir que vous avez effacer son compte et supprimer certains de ses messages. Comme j'étais en train de rédiger un long commentaire pour exposer sa profonde ignorance au grand jour et que je ne veux pas avoir perdu du temps pour rien, je le mets quand même ici. Il pourra servir comme référence, au cas où il revienne avec un autre compte.

    Voici une analyse de sa confiture que nous ne savons pas apprécier au sujet de l'article de Ken Thompson.

    Le cas Ken Thompson

    Alors que Ken Thompson reçoit le prix Turing en 1983 pour son œuvre, lors de son discours de remerciement, il présente le programme le plus malin (cutest)1 qu'il ait jamais écrit. Son discours est retranscrit sous forme d'article et publié dans un bulletin de l'ACM sous le titre Reflections on trusting trust.

    Le programme en question est fortement lié au présent journal, puisqu'il consiste à corrompre un compilateur C dans la chaîne de bootstraping, de tel sorte que tout compilateur C qui lui succède introduise une porte dérobée dans le programme de login d'un système Unix.

    Son exposé se décompose en trois étapes que nous présenterons brièvement dans ce qui suit.

    Étape 1

    La première étape consiste à écrire un programme qui, lorsqu'il s'exécute, reproduit son propre code source sur la sortie standard. Un tel programme est dit autoreproducteur. En voici un exemple minimal en OCaml :

    (fun x -> Printf.printf "%s %S" x x) "(fun x -> Printf.printf \"%s %S\" x x)";;
    (* ci-dessous le retour de l'exécution, identique au code source *)
    (fun x -> Printf.printf "%s %S" x x) "(fun x -> Printf.printf \"%s %S\" x x)"

    Étape 2

    La seconde étape traite un problème posé dans un autre commentaire du journal par redo_fr : comment ajouter de nouvelles fonctionnalités à un langage en compilant le nouveau compilateur avec une version antérieure, qui ignore, donc, les nouvelles fonctionnalités ?

    Il y traite un exemple simple avec l'interprétation des séquences d'échappement dans les chaînes de caractères. Il montre comment boostraper l'interprétation de la séquence \v comme une tabulation verticale. Ainsi, même si, à la génération N, la séquence \v n'est pas valide, à partir des générations N + 1 et suivantes, tous les compilateurs pourront l'utiliser dans leur propre code source.

    Étape 3

    C'est l'étape finale où il décrit comment introduire la porte dérobée sans laisser aucune trace dans le code source du compilateur.

    Dans une représentation idéalisée du fonctionnement d'un compilateur, celui-ci lit le code source du programme puis applique une routine compile(s) sur les parties du code. Pour introduire une porte dérobée, on peut tester la correspondance de la fonction à compiler sur un motif donné et introduire dans ce cas compile(backdoor).

    Le défaut de cette approche est que même une lecture superficielle du code source du compilateur risque de découvrir le pot aux roses, en voyant l'exécution conditionnelle de l'instruction compile(backdoor).

    La solution consiste, alors, à combiner les techniques des deux premières étapes afin d'effacer la supercherie du code source du compilateur. À la génération N, on introduit la porte dérobée sous forme d'un programme autoreproducteur (étape 1), que l'on boostrape (étape 2), puis l'on distribue ce binaire comme compilateur C officiel qui reproduira son comportement dans toutes les générations successives.

    Le lecteur intéressé par les détails de chaque étape pourra toujours se reporter à l'article de Ken Thompson.

    Maintenant, chers lecteurs, attardons nous quelque peu sur l'analyse détaillée de cette succulente confiture gracieusement offerte par SamWang, que, nous autres, pauvres cochons, n'avons pas su éstimer à sa juste valeur. Ça vaut le détour ! :-)

    La recension de SamWang

    Lui, ô grand chasseurs devant l'éternel de coquilles, coquillages et autres crustacés, se propose de nous révéler quelques une de ses prises, suite à sa lecture du papier l'été dernier. Et quelles prises ! :-D

    Avant cela, il tente un résumé de l'article qu'il semble n'avoir pas totalement saisi. Pour lui, l'article expose l'injection d'une porte dérobée dans la compilation du fichier login.c. Puis Ken Thompson mettrait ensuite « en garde contre le risque d'injection de code malveillant par un compilateur malveillant dans tout programme qu'il compile, y compris un compilateur ». J'espère que tout lecteur attentif de ma présentation aura compris que c'est un peu plus subtil que ça.

    Passons, à présent, aux coquilles mineures relevées. Il en trouve deux :

    • inversion de légendes entre deux figures du papier ;
    • placement de figures dans la mauvaise section.

    S'il y a bien inversion de légende entre deux figures (celles qui illustrent comment ajouter la séquence d'échappement \v au langage) et que tout lecteur attentif corrigera de lui-même, je suis au regret de lui apprendre que la seconde n'en est pas une.

    SamWang ne devant pas être habitué à la lecture d'article académique, il a pris pour une coquille ce qui n'est rien d'autre qu'une mise en page, on ne peut plus classique, dans ce genre de papier. Les figures liées à la section 2 sont reportées en bas de page, qui, dans le cas présent où chaque page est en format deux colonnes, se trouve en bas de la seconde colonne. Cela lui donne l'illusion qu'elles sont insérées dans la section 3 dont le texte commence sur cette deuxième colonne.

    C'est déjà quelque peu amusant, mais le plus beau reste à venir. Dans le fond, SamWang a une âme d'explorateur : il rêve d'une terre remplie de K-zino, avec son comparse zind dans sa logique LFC, inspirée des travaux de Rudolph Carnap, pour faire de la LNC. Malheureusement pour lui, depuis dix ans qu'il en parle, il ne navigue toujours par sur l'océan à la recherche de la terre promise. Nulle Santa Maria, ni même le moindre radeau, et tous ses bateaux semblent prendre l'eau. Alors, seul sur le rivage, admirant au loin l'horizon, il doit s'ennuyer un peu : il part donc à la pêche aux coquillages.

    Et là, mazette, quelle récolte ! Ken Thompson ne sait même pas écrire correctement du C. Oui, vous avez bien lu : Ken Thompson est une bille en C, il ne sait pas écrire un programme de quelques lignes syntaxiquement valide, et en plus il propose ça en publication à l'ACM qui valide le tout. Mais dans quel monde vit-on ?

    Voyons voir cette grossière erreur un peu plus à la loupe. Elle se trouve dans l'étape 1, lorsqu'il traite des programmes autoreproducteurs. Son code commence par la déclaration d'une chaîne de caractères :

    char s[] = {'t', '0', '\n', '}', ';' ... }

    Puis, dans la boucle principale, il parcourt cette chaîne pour l'imprimer caractère par caractère. Ni une, ni deux, SamWang arrive à la conclusion fatidique : si je commence par écrire cette séquence de caractère au tout début d'un fichier, je n'aurais pas un code source C valide. En conséquence, alors que le programme d'exemple devait afficher son propre code source, il affiche un texte qui n'est même pas valide en C. Quel escroc ce Ken Thompson ! encore un qui essaye de jouer au paralogisme, mais on n'échappe pas à la surveillance assidue du SamWang.

    Rassurez vous, rien de tout cela dans le code de Ken Thompson, c'est juste que l'idiot de service à oublier de lire l'instruction qui précède la boucle for :

    printf("char\ts[] = {\n");

    C'est vrai que, finalement, il a un certain sens de l'humour notre SamWang : certes à ses dépends, mais c'est drôle quand même. :-)

    Après, pour être tout a fait exact, son exemple n'est pas un programme autoreproducteur mais génère un tel programme. Il le précise lui même :

    The purist will note that the programm is not precisly a self-reproducing programm, but will produce a self-reproducing programm

    Ken Thompson

    Ce qui est encore plus drôle (deuxième effet kiss cool) est que, à la toute fin de son commentaire, SamWang pointe un lien vers un vrai programme autoreproducteur « dans lequel le tableau de données est lu deux fois et interprété différemment les deux fois.[...] une solution bien astucieuse » (les mots sont de SamWang). Tout lecteur de bonne foi, comprenant le C, réalisera sans peine que cette solution astucieuse est identique, dans l'esprit, à celle de Ken Thompson.

    Comme autre perle de sa pêche aux coquillages (heureusement que je sais ouvrir les huîtres), on trouvera celle-ci. S'interrogeant sur l'utilité de cette étape dans le corps de l'article, notre cher ami écrit, je cite :

    Je suppose que s'il passe par cette étape, c'est pour justifier la possibilité, pour un compilateur malveillant, d'injecter sa malveillance en tant que code source ajouté au code source légitime qu'il compile. Bien que son propos manque d'articulation logique, je pense qu'on peut légitimement inférer ce que je viens de supposer.

    SamWang au sommet de sa forme.

    Je laisse le lecteur libre de juger à quel point l'étape 1 est cruciale pour l'étape 3 (d'après ma présentation), et si, dans son article, Ken Thompson ne le signale pas explicitement selon une articulation logique sans faille. Ce qui manque, assurément, d'articulation logique, ce sont les commentaires à ralonge de SamWang.

    Arriver à ce stade, toute personne sensée, avec un minimum d'humilité, aurait du se dire : « j'ai du raté un truc » (en l'occurrence oui, à savoir, une ligne de code). Mais comme rien n'arrête notre SamWang, il va bien plus loin : par une réduction à l'infinie, il entend, dans un premier temps, nous convaincre que le problème que cherche à résoudre Ken Thompson n'a même pas de solution. Non seulement il ne peut toujours pas naviguer sur l'océan à la recherche de découverte pleine d'espérance, devant se contenter du rivage et de ses coquillages, mais le voilà maintenant chutant inexorablement dans le tonneau des danaïdes, ce puit sans fin dont il desespère de ne pas voir le fond.

    Ce genre de problème de point fixe est on ne peut plus courant, mais il semble l'ignorer : étant donné une fonction f trouver une valeur x tel que f (x) = x ; où ici la fonction f, dont on cherche un point fixe, est la composée de deux autres f = run . compile, de telle sorte que l'on cherche source satisfaisant l'équation :

    (run . compile) (source) = source
    

    Il se met alors à chercher des contournements au défi, en assouplissant les contraintes, afin d'y arriver. Il envisage, par exemple, un programme qui ouvre son fichier source puis l'affiche, ce qui nécessite d'avoir toujours à disposition le code source d'un tel programme. Là où l'on voit qu'il n'a rien compris à l'article, étant donné que le compilateur compromis ne sera distribué que sous forme binaire tout en ayant la capacité de « parasiter » tous les futurs compilateurs qui
    l'auront comme ancêtre.

    Incompréhension totale de l'article confirmée par ce qui conclut cette partie du commentaire (qui constitue la moitié, en volume, du commentaire complet) :

    Tout ceci étant exprimé, est-il impératif d'avoir une solution viable au défi pour que l'exposé de Ken Thomson tienne la route par ailleurs ? Ma réponse est non.

    SamWang dans sa chute ne voyant toujours pas le fond

    Assurément que si, c'est impératif ! comme je viens de le rappeler.

    Enfin, nous touchons au sublime avec la conclusion du commentaire, où, sautant du coq à l'âne, dans une articulation logique à toute épreuve, l'on apprend dans la foulée de cette question-réponse que, si, finalement, on peut écrire des programmes autoreproducteurs et que l'on appelle cela des quine (en l'honneur du philosophe analytique William Quine, je précise). SamWang a donc passé la moitié de son commentaire à nous expliquer que c'est pas possible, pour, finalement, nous dire que c'est possible. Effectivement, ça valait le coup ! :-D

    Non vraiment, je ne vois pas ce qui a bien pu m'amener à écrire :

    Pour le reste tu passes ton temps à essayer d'employer des notions et des concepts auxquels tu n'entends absolument rien, et cela face à des personnes qui, elles, les comprennent.

    et le voir me répondre :

    Bing ! La formule magique, l'échappatoire à deux sous !

    Ce qui précède doit bien apporter la preuve irréfragable de ce que j'avançais. Pour ce qui est de l'autre fil de discussion, ce n'est guère mieux, mais j'ai déjà assez perdu de temps comme cela pour devoir le justifier.


    1. l'adjectif anglais cut, outre sa signification de mignon, peut aussi caractérisé quelque chose d'habile et d'ingénieux. En choisissant la traduction « malin », on retrouve le côté ingénieux d'un hack, ainsi que celui malveillant (par un jeu de mot) d'une attack. ;-)

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.