La vie est mal configurée

Aller au contenu | Aller au menu | Aller à la recherche

mercredi, août 15 2018

Absence de hiérarchisation

Je lis souvent que ParcourSup ne demanderait pas de « hiérarchisation des vœux » aux candidats, et que cela expliquerait certaines décisions surprenantes de ce processus (e.g. mettre en géographie un candidat qui voudrait faire des mathématiques). Le sous-entendu est qu’en l’absence de hiérarchisation, le processus affecte les candidats sans tenir compte de leurs préférences.

Or, ParcourSup, même si cela est moins évident que pour APB, suppose une certaine hiérarchisation des vœux par le candidat ! En effet, à chaque étape de ParcourSup où il se voit proposer des offres fermes, le candidat doit désigner parmi ces offres fermes celle qu’il préfère, et démissionner des autres.

La différence avec APB est qu’avec APB on demandait au candidat de classer au préalable tous ses vœux par préférences décroissantes, alors qu’avec ParcourSup on ne l’interroge que sur certaines comparaisons de préférences, celles effectivement nécessaires au fonctionnement du processus. Par comparaison, APB exigeait des informations dont il n’aurait pas besoin (si on est classé trop loin par une formation pour y avoir une place, les comparaisons de préférence entre cette formation et les autres n’ont aucune importance et ne sont pas consultées par l’algorithme).

J’ai de grandes réserves quant à un processus qui exige de multiples étapes de consultation où les candidats doivent impérativement avoir une connexion Internet fiables, et ne donne que tardivement des affectations définitives tant aux formations qu’aux candidats, d’où des difficultés à s’organiser. Il ne faut cependant pas confondre la lenteur de convergence d’un processus avec le calcul d’un résultat arbitraire.

mercredi, juillet 25 2018

L'incroyable étant réel, où finit le plausible ?

J’ai expliqué être opposé aux machines de vote électronique car j’estime qu’en cas de contestation, il serait impossible à l’expertise technique de convaincre les électeurs de l’absence de tricherie. On m’a demandé s’il ne s’agissait par là d’une forme de renoncement.

Le scientifique doit-il renoncer à son expertise au motif que des complotistes pourraient l’accuser de malhonnêteté ? La raison doit-elle s’incliner devant la croyance et la partialité politique ? Sans doute non. Toutefois, rejeter toute méfiance comme relevant du complotisme irrationnel, et donc à ignorer, est à mon avis une mauvaise analyse.

Si l’on m’avait dit, il y a quelques mois qu’un proche du Président de la République se faisait passer pour un policier pour pouvoir rouer de coups des manifestants, peut-être par sadisme, j’aurais dit qu’il s’agissait d’un excellent scénario pour un film censé se passer dans une dictature sud-américaine des années 1970, mais que c’était « trop gros » pour se passer en France. Et pourtant, des choses « trop grosses » se sont passées, avec des complicités multiples.

L’incroyable d’hier est devenu le réel d’aujourd’hui. Si pareilles choses sont possibles, il est rationnel de penser que d’autres, moins visibles, le sont, et il est donc rationnel d’être méfiant !

mardi, juillet 24 2018

Intelligence artificielle et calculabilité

À une récente demi-journée d’études sur intelligence artificielle et sciences humaines et sociales, deux intervenants ont soulevé la question de la calculabilité et de l’indécidabilité. Un échange de courriels s’est ensuivi, notamment avec mon collègue Denis Trystram. Je vais résumé ici ma position, qui me semble la même que celle de Denis.

La théorie de la calculabilité établit des bornes à ce qui est calculable par un algorithme, par une version idéalisée d’un ordinateur. Comme résultats notables on a :

  1. Quelle que soit la propriété que l’on veut vérifier sur un programme, plus précisément sur la relation entre les données fournies en entrée et le résultat du calcul, il n’existe aucun algorithme qui permette de décider à coup sûr si un logiciel la vérifie. Autrement dit, il n’existe aucun algorithme capable de décider si un logiciel est correct au vu du code du logiciel. (Théorème de Rice, extension du théorème de l’arrêt de Turing.)

  2. Il n’existe aucune procédure qui dise si un énoncé mathématique est vrai ou faux. (Je simplifie beaucoup, pour plus de précision voir les énoncés des théorèmes d’indécidabilité de Gödel, et aussi le théorème d’indéfinissabilité de Tarski.)

Cette théorie est complétée par celle, un peu plus récente, de la complexité, qui établit notamment qu’il y a des problèmes pour lesquels il existe certes des algorithmes, mais forcément de coût prohibitif.

On a parfois prétendu que ces théorèmes établissent la supériorité de l’esprit humain sur la machine et, comme dans ce colloque, on s’est interrogé sur le lien avec l’intelligence artificielle.

Si, par le passé, on a rangé dans l’intelligence artificielle la réponse à des problèmes dont la définition était très strictement posée en termes mathématiques (démontrer des théorèmes, gagner aux échecs…), l’attention actuelle porte sur des problèmes qui, justement, ne sont pas définis mathématiquement et où l’enjeu consiste en fait à extraire une forme de définition d’une accumulation d’exemples (par exemple, on va apprendre à la machine à reconnaître un mouton en lui montrant une grande quantité de photographies et en lui disant lesquelles contiennent des moutons). Il s’agit par ailleurs souvent de problèmes flous, où il y a des cas tranchés et d’autres où plusieurs réponses seraient admissibles.

Les théorèmes de calculabilité et de complexité ne s’appliquent qu’à des propriétés bien définies mathématiquement. Par exemple, le fait qu’un problème soit de complexité élevée exclut qu’il existe un algorithme efficace dans tous les cas, mais n’exclut pas qu’il existe un algorithme efficace en pratique sur les cas industriellement utiles, car le concept de « cas industriellement utile » est mal défini.

Le rapport entre les questions d’intelligence artificielle proprement dites étudiées actuellement et les résultats classiques de calculabilité ne me semble donc pas évident.

dimanche, juillet 22 2018

La grande incertitude de la recherche mathématique

Quelle différence y a-t-il entre l’enseignement et la recherche en mathématiques ? Bien évidemment, il y a une différence de degré d’abstraction et de technicité entre l’enseignement, a fortiori secondaire, et la recherche. Je pense toutefois que la différence la plus importante est que lorsque l’on est élève, on sait ce que l’on doit faire, alors qu’en recherche, non.

Lorsqu’un·e enseignant·e pose un problème de mathématiques, il ou elle a en tête une façon de le résoudre en n’utilisant que les connaissances que l’étudiant·e est censé·e avoir à ce moment, et la décompose en étapes telles que chacune soit faisable sans trop de questionnements. C’est ce qui permet de poser en travaux dirigés, voire en examen, ce qui a jadis été une question de recherche. Par exemple, j’ai une feuille de travaux dirigés presque faisable en deux heures pour de bons étudiants où l’on démontre le théorème de complétude de la logique du premier ordre, lequel constituait pourtant la thèse de doctorat du célébrissime logicien Kurt Gödel.

À l’opposé, en recherche (à tout niveau), on ne sait en général pas si le résultat que l’on compte prouver est vrai, puisque c’est la démonstration que l’on cherche qui établirait cette vérité (il arrive toutefois que l’on cherche à redémontrer un théorème par une autre méthode, ce qui peut être instructif). Bien entendu, on ne va pas à l’aveuglette, on est guidé par des indices : par exemple, si des calculs numériques (approximés) semblent indiquer qu’une quantité est nulle, il est raisonnable d’essayer de le démontrer. Il est cependant périlleux de conclure que parce qu’une chose semble vraie elle l’est forcément, et plusieurs conjectures qui semblaient raisonnables ont été par la suite démontrées fausses.

Plus profondément, le mathématicien en recherche non seulement ne sait pas si le résultat qu’il cherche à démontrer est vrai ou faux, mais doit en premier lieu poser les bonnes questions, les bonnes définitions. Il ne s’agit donc pas simplement de réaliser un « tour de force » en démontrant un résultat, mais surtout de construire un édifice conceptuel (que l’on nomme souvent théorie : théorie des distributions de Laurent Schwartz, théorie de Ramsey, etc.). Pour ma part, je n’en suis pas là : je démontre modestement des petits résultats.

Quelques exemples de ce phénomène en action. Il y a quelques années, je m’étais demandé si la raison pour laquelle on avait proposé tant de méthodes partielles pour inférer ce que l’on appelle des invariants inductifs polyédraux n’était pas qu’il ne peut exister de méthode algorithmique totale. Ce problème traînait dans mon esprit. J’ai démontré un résultat plus faible que celui que j’aurais voulu ; mais peut-être est-ce que parce que le résultat plus fort serait faux ? Je n’en sais rien ! J’ai interrogé des collègues (Olivier m’a dit de demander à Joël, Joël m’a dit de demander à Olivier, etc.) ; personne ne savait comment prendre la question. De guerre lasse, plusieurs années plus tard, j’ai fini par publier mon résultat trop faible à mon goût.

Actuellement, Valentin Touzeau, doctorant, et moi-même tentons de démontrer des résultats sur la complexité de certains problèmes, c’est-à-dire leur degré de difficulté lorsqu’il s’agit de les résoudre par un algorithme (je simplifie). Avant de nous lancer là-dedans, nous ne savions pas quels résultats nous pourrions prouver (si ce n’est quelques bornes larges et évidentes pour qui connaît ce genre de questions). J’ai pu prouver qu’un des problèmes en question est NP-complet (c’est une des classes de complexité), et Valentin me dit qu’il a une idée pour montrer qu’un autre de ces problèmes est PSPACE-complet (c’est une autre classe). Je suis très excité par cette perspective, mais je reste prudent : nous ne devons pas crier victoire tant que nous n’avons pas une preuve rédigée au propre !

Si je suis excité, c’est parce que le résultat ainsi démontré correspondrait à une intuition souvent citée par les gens qui proposent des algorithmes pour résoudre partiellement les problèmes en question pour expliquer pourquoi le second est plus difficile que le premier. Mais je n'en sais toujours rien.

samedi, juillet 21 2018

Politiques publiques et Internet : 2006-2018, rien ne change

Le Parlement européen n’a pas adopté un projet de directive sur le copyright. Les réactions, suite à cette décision, m’ont rappelé celles au moment du projet de loi DADVSI en 2006, puis du projet de loi HADOPI, ou encore celles autour de Wikipédia. On peut même dire qu’elles étaient très prévisibles ! Je les analyse au prisme du rapport légitime au pouvoir que certains groupes exercent, et leur disqualification des autres points de vue.

Lors de l’examen des projets de loi DADVSI et HADOPI, certains avaient dénoncé les campagnes de courriers et messages hostiles au projet de loi, les décrivant comme des « pressions » intolérables envers les élus. S’agit-il de dire que de simples citoyens, certes nombreux, n’ont pas à se mêler du processus législatif ? Pourtant la Déclaration de 1789 dit « La Société a le droit de demander compte à tout Agent public de son administration. »…

Dans le même temps, les industriels du secteur, les sociétés professionnelles, les intermédiaires (notamment les sociétés de perception et répartition des droits, les SPRD) ne se privent pas d’interventions auprès des élus. Ainsi, un assistant parlementaire m’avait expliqué, à l’époque, que la sénatrice qui l’employait avait construit sa carrière sur sa proximité avec ce milieu et qu’en conséquence il ne fallait pas s’attendre à ce que, quels que soient les arguments entendus, elle n’en adopte pas les propositions. On se rappellera également d’amendements présentés simultanément et séparément par des parlementaires de plusieurs groupes, dont on peut donc raisonnablement penser qu’ils étaient suggérés, argumentaires compris, par des groupes défendant des intérêts privés — on attribuait certains amendements au groupe Vivendi Universal, j’ignore ce qu’il en était. On se rappellera également qu’Alain Suguenot, député-maire de Beaune, avait fait état de pressions contre lui (menaces de retrait des professionnels d’un festival à organiser dans sa ville).

Comment analyser cette disparité de traitement ? Il y a d’un côté des messages légitimes, émis par des groupes qui estiment normal d’avoir accès aux élus pour faire valoir leurs intérêts, et de l’autre des messages illégitimes. Lorsque ces derniers sont entendus, ceux qui s’estiment les seuls à avoir droit au chapitre expriment publiquement leur indignation.

Selon un argumentaire bien rôdé, les groupes s’opposant à certains projets ou soutenant certaines mesures qui n’agréent pas aux industries culturelles seraient forcément financés par les « GAFA » (Google, Amazon, Facebook, Apple, et plus généralement les grandes entreprises de l’Internet, souvent américaines). Là encore, l’accusation n’est pas neuve : on se rappellera que certains accusaient Wikipédia d’être financée par Google !

S’il est légitime de s’interroger sur les financements de certaines associations intervenant dans le débat politique, pourquoi serait-il illégitime de s’interroger, par exemple, sur les éventuelles activités libérales de certains universitaires (économistes, juristes) intervenant dans ce débat, susceptibles de donner lieu à conflit d’intérêts ? Pourtant, on n’entend jamais ces questions dans les médias. Là encore, il paraît légitime de suspecter certains (même si l’on n’a pas le moindre début de preuve), et illégitime de s’interroger sur d’autres tant est grande leur respectabilité.

Un autre argument classique est que les nouveaux circuits du divertissement permettent à certains intermédiaires (Google, etc.) de s’enrichir indûment. Il est très possible que cela soit le cas ; ce n’est pas mon propos d’en disputer ici. En revanche, il est très intéressant de constater que ceux qui se plaignent de ces nouveaux circuits et s’interrogent sur la destination des profits ainsi réalisés refusent tout débat sur la destination des profits réalisés par les circuits plus classiques. Il me semble d’ailleurs (mais je peux être mal informé) qu’il règne une grande opacité sur la répartition des profits entre les artistes et les industries et intermédiaires. Cela est d’autant plus regrettable que dans les débats, on n’a à la bouche que la préservation des artistes et de leurs revenus, et qu’on ne manque pas de témoignages d’artistes, au fil des décennies, se plaignant d’avoir été exploités par leur maison de disques, leur producteur, etc. Un débat éclairé ne peut se contenter d’arguments dénonçant une évolution récente sans pour autant analyser la situation antérieure. Là encore, la situation antérieure est présumée légitime, l’évolution illégitime.

Enfin, revient l’accusation que les groupes opposés à certaines réglementations concernant Internet seraient des « anarchistes ». Accusation commode, l’anarchie étant censée être une option politique extrême et irréaliste — la ficelle est ancienne ! Là encore, l’idée sous-jacente semble être que les seuls points de vue politiques légitimes sont ceux consistant à ajuster les paramètres du jeu social en faveur des grands intérêts préexistants.

Ainsi, les débats politiques autour d’Internet sont globalement prévisibles : les positions, les postures, des uns et des autres sont connues. Le cadre dirigeant de SPRD parle au nom des artistes avec l’aplomb de celui qui estime qu’on doit l’écouter et accéder à ses demandes. Les activistes d’Internet, les « gusses dans un garage » selon une expression d’une ministre de la culture, crient à la censure. Les premiers accusent les seconds de faire le jeu des GAFA. Rien ne change !

Ce qui devait arriver est arrivé

Mes lecteurs savent qu’une des principales raisons pour lesquelles je suis opposé au vote électronique pour les élections à grands enjeux, c’est que s’il devait y avoir une contestation (allégations de « piratage » ou de malversations), les experts scientifiques et techniques seraient placés dans une situation impossible : leurs propos seraient incompréhensibles pour le grand public, des gens relèveraient comme scandaleuses de simples remarques techniques, et on attribuerait le jugement des experts à leurs préférences politiques.

La polémique autour du système « ParcourSup » d’attribution des places dans l’enseignement supérieur illustre bien mes craintes : il s’est passé ce que je craignais comme ci-dessus. Des gens se répandent sur les réseaux sociaux en expliquant que très certainement mes collègues Claire Mathieu et Hugo Gimbert, concepteurs (à un degré que j’ignore) de ce système, sont « macronistes ».

Je ne suis aucunement surpris. À une autre époque, des gens avaient émis l’hypothèse que j’étais des amis d’Alain Finkielkraut car j’avais enlevé de sa biographie Wikipédia l’affirmation qu’il était un journaliste d’extrême-droite (je n’ai vu Alain Finkielkraut en chair et en os qu’une fois dans ma vie et n’ai jamais parlé avec lui), ou encore que j’avais corrigé la biographie de Monique Canto-Sperber au motif que je lui étais redevable au motif que je lui aurais dû ma place au LIENS (quiconque sait comment fonctionne le CNRS sait que cela est une idée délirante). Plus récemment, j’ai vu des tracts expliquant (je résume rapidement) que mon laboratoire fait des recherches militaires utilisables par Frontex (là encore, quiconque sait ce que nous faisons rira jaune).

Devant l’impossibilité d’un débat serein, devant l’omniprésence des attaques ad hominem, le plus simple me paraît être d’éviter le recours à des dispositifs d’intérêt douteux et qui susciteront le doute quant au processus démocratique, doute qui ne sera pas levé par les explications des spécialistes.

samedi, juin 2 2018

Algorithme vs logiciel

Lors des débats actuels sur ParcourSup, ou à des discussions antérieures au sujet d’« algorithmes » utilisés à différentes fins en rapport avec la société, j’ai vu des questions sur la différence entre « algorithme » et « logiciel ». Je vais ici tenter d’expliquer les différences et similarités entre ses deux concepts.

Prenons un exemple simple : nous avons un tableau de nombres (par exemple 16, 3, 45, 2, 7, 32, 42, 51) et nous voulons les classer par ordre croissant. Ceci est la spécification de notre algorithme : nous spécifions ce que nous désirons obtenir.

Un algorithme possible pour cette tâche de tri est le suivant : on recherche dans le tableau le plus petit nombre, on l’intervertit avec le nombre en première position, puis on recommence pareil sur le reste du tableau privé du premier élément, puis sur le reste du tableau privé du deuxième élément, et ainsi de suite jusqu’à la fin du tableau. (On le connaît dans les cours d’algorithmique sous le nom de tri par sélection.)

Voyons maintenant pourquoi cet algorithme est correct, c’est-à-dire qu’il fait bien ce que nous voulons. Tout d’abord, la sortie est triée : on a bien le plus petit nombre en premier, puis le plus petit parmi les nombres restants, etc. Par ailleurs, cette sortie a bien le même contenu que l’entrée, ce sont bien les mêmes données dans un autre ordre, puisqu’on ne procède que par permutations.

Remarquons que la description de cet algorithme est incomplète : je n’ai pas dit comment je recherche le plus petit nombre dans le tableau. C’est parce que la méthode précise par laquelle je recherche ce plus petit nombre importe peu pour garantir le bon fonctionnement de mon algorithme de tri : ce qui importe c’est qu’on me donne ce nombre, ou plus précisément sa position dans le tableau. J’écris pour que des humains me lisent, je ne vais pas les surcharger de détails !

En revanche, si je programme un logiciel qui procède à un tri, je suis bien obligé de régler tous les détails : comment le tableau est stocké dans l’ordinateur, quelle procédure de recherche du plus petit élément j’utilise. La langue naturelle est imprécise et par ailleurs difficile à faire comprendre par un ordinateur, aussi je décris mon logiciel dans un langage de programmation qui me permet de décrire précisément les étapes de calcul que je désire faire effectuer par l’ordinateur.

Notons qu’un logiciel complet ne se limiterait pas à un unique algorithme : il faut une interface utilisateur (dont l’affichage nécessiterait d’autres algorithmes), des traitements de situations d’erreurs, etc. Tout ceci peut paraître facile et de peu d’intérêt, mais il me semble que, dans la grande majorité des logiciels, la plus grande partie du code du logiciel concerne ces aspects et non des algorithmes délicats.

Revenons à notre algorithme de tri. Étant donné un tableau de nombres passé en entrée, il n’existe qu’une seule sortie permise par la spécification : un tableau avec le même contenu mais trié dans l’ordre. Peu importe la façon dont on a procédé ! Imaginons maintenant qu’il s’agisse d’un tableau de noms d’élèves avec leurs notes, que l’on va trier par notes croissantes. Nous n’avons pas dit comment départager les ex-æquo, aussi, suivant l’algorithme de tri utilisé, nous pourrions avoir plusieurs sorties possibles dans ce cas. Notre spécification est alors incomplète.

Lorsque la spécification est complète (on a complètement défini d’avance le résultat attendu), ni le choix de l’algorithme ni les détails de fonctionnement du logiciel ne nous importent, puisque, quelle que soit la façon dont on s’y prend, il y aura toujours le même résultat au bout. Il nous faut toutefois nuancer cette affirmation.

Le choix de l’algorithme et les détails de fonctionnement du logiciel ont leur importance en ce qui concerne le temps de calcul. Par exemple, l’algorithme de tri que j’ai décrit ci-dessus est très mauvais sous cet aspect : le nombre d’opérations qu’il nécessite croît avec la taille du tableau d’entrée beaucoup plus vite que le nombre d’opérations utilisées par d’autres algorithmes, de sorte que son coût serait prohibitif sur une grosse base de données (et donc une personne compétente ne l’emploiera jamais que sur de petits tableaux).

Par ailleurs, nous pouvons aussi soupçonner qu’il y a des écarts entre l’algorithme « idéal » décrit sur le papier, et ce qui a été effectivement mis en œuvre dans le logiciel, qu’il s’agisse de « bugs » involontaires ou d’altérations censées répondre à certaines contraintes mais pas forcément bien maîtrisées. Il ne suffit donc pas d’avoir la spécification ou l’algorithme idéal pour vérifier qu’un logiciel répond à la demande.

PS On me souffle des analogies : l'algorithme c'est le plan, la théorie; le logiciel, la réalisation, la pratique. La mienne : l'algorithme c'est un thème musical, le logiciel c'est l'interprétation complète d'un morceau comportant plusieurs thèmes orchestrés.

mercredi, mai 30 2018

APB, ParcourSup et les méchants algorithmes

Voici ce que je comprends d'APB et ParcourSup, expliqué en termes compréhensibles du grand public. Merci de me corriger en cas d'erreur.

« Dans le temps », quand on passait les concours de certaines grandes écoles, celles-ci établissaient une « liste principale » d'admis et une « liste complémentaire ». Les admis sur la liste principale étaient appelés, et s'ils démissionnaient (habituellement, parce qu'ils étaient admis dans une autre école qu'ils préféraient), on appelait des candidats sur la liste complémentaire, qui eux-mêmes pouvaient démissionner. Bref, si l'on était sur la liste principale on savait que l'on était admis, mais on en était aussi quasi sûr si on n'était pas trop loin sur la liste complémentaire, au vu de ce qui s'était passé les années précédentes.

Le procédé était toutefois laborieux : tout n'était pas centralisé (il me semble qu'il y avait un service Minitel, mais pour certains concours seulement) et il y avait, au moins pour certaines écoles, des courriers papier qui s'échangeaient (on recevait une convocation pour admission et il fallait répondre par courrier pour démissionner). Tout ceci faisait que certains candidats étaient finalement admis en septembre, à quelques jours de la rentrée, en général dans un établissement éloigné du logement parental. Heureusement que ces établissements sont dotés de résidences !

Une première amélioration consiste à tout centraliser sur un unique service télématique, au lieu d'utiliser des courriers et des services séparés. Par ailleurs, pour assurer une réponse raisonnablement rapide, il faut empêcher qu'un étudiant hésitant puisse bloquer les autres, donc on va exiger qu'entre plusieurs offres fermes d'admission il ne puisse en choisir qu'une (sa préférée parmi celles proposées), et ainsi libère les autres. C'est le fonctionnement de ParcourSup.

Notons qu'avec ce système, il n'y a pas obligation de se désister de formations sur lesquels on est encore en attente, même si l'on sait que l'on est admis sur une formation qu'on leur préfère ; on me dit que certains lycéens tergiversent ainsi, ce qui prolonge les incertitudes des autres.

On peut alors se demander pourquoi demander au candidat à chaque fois de choisir sa préférée parmi les offres fermes déjà proposées, alors qu'il suffirait de lui demander une fois pour toutes son ordre de préférence : le programme peut alors répondre de lui-même à la question de l'offre préférée parmi celles présentées, et on peut affecter rapidement les étudiants dans les formations sans avoir à leur poser des questions à plusieurs reprises. C'est le fonctionnement de l'algorithme à la base d'APB (algorithme de Gale & Shapley version « optimale pour les universités »).

Si tout est si simple et compréhensible, pourquoi toutes ces controverses sur l'opacité des algorithmes, les tirages au sort etc. ? Tout d'abord, sur APB.

APB concernait des formations sélectives et non sélectives. Les formations sélectives classent leurs candidats et peuvent en refuser certains, les formations non sélectives (la plus grande partie des licences universitaires) ne le peuvent pas, et doivent donc a priori accepter tout candidat avec le baccalauréat — quel que soit la série de celui-ci et l'adéquation avec les études envisagées. Cependant, une formation non sélective peut avoir une limite de capacité, ne serait-ce qu'en raison de contraintes de locaux, d'équipements et de personnels enseignants. Dans ce cas, APB départageait les candidats par tirage au sort.

Il n'y a évidemment aucune fatalité à devoir utiliser un tirage au sort si l'on utilise un algorithme d'affectation. En revanche, si, suite à des décisions politiques (refus d'accorder plus de moyens, refus de classer ou sélectionner les candidats) on se retrouve avec plus de candidats que de places, il faut bien un moyen pour les départager, qu'on utilise un procédé automatisé ou non.

On dit que l'algorithme d'APB donnait un bonus au premier choix des candidats. On dit également qu'au moins certaines années, les formations étaient informées du classement que le candidat leur attribuait. Ceci fausse les bonnes propriétés de l'algorithme de Gale & Shapley. On peut éviter tout doute à ce sujet en demandant aux candidats leurs préférences quant aux formations sur lesquelles ils candidatent après que celles-ci aient rendu leurs classements.

Par ailleurs, ni APB et ParcourSup ne sont strictement basés sur un classement (fût-il obtenu par tirage au sort). Ils prennent en compte des critères de résidence, de taux de boursiers, et de places en internat. Tout ceci complexifie considérablement le problème à résoudre et éloigne le fonctionnement de l'algorithme des principes simples évoqués plus haut.

Enfin, dans le cas de ParcourSup, ainsi que dans le cas des formations sélectives pour APB, il y a la question du classement des candidats par les formations. Dans les concours classiques des grandes écoles, ce classement est obtenu par des écrits anonymisés et des oraux menés par un jury restreint, avec des harmonisations et des coefficients connus et publiés d'avance. Dans le cas de ParcourSup, on se base sur des notes de lycée non harmonisées, des appréciations d'enseignants, des lettres de motivation, selon des processus tenus secrets que l'on a parfois qualifiés d'« algorithmes locaux » — c'est un bien grand mot pour désigner ce qui, dans certains cas en tout cas, est un classement selon la moyenne avec coefficients de certaines notes de lycée.

samedi, mai 26 2018

Un humain tellement inhumain

La ministre de l’enseignement supérieur et de la recherche, Mme Frédérique Vidal, a expliqué qu’un des buts de ParcourSup par rapport à APB est de « remettre de l’humain » ; à l’opposé certains jugent « inhumain » le nouveau processus. Humain, inhumain, voilà qui mérite une petite analyse de vocabulaire.

Clairement, Mme Vidal considère qu’un processus plus humain est intrinsèquement meilleur, comme, dans d’autres contextes (alimentation, pharmacie), on considère souvent de nos jours que ce qui est « naturel » est intrinsèquement meilleur. L’« humain », le « naturel », sont considérés comme bons, par opposition à l’automatique, à l’artificiel, considérés comme mauvais.

Pourtant, quoi de plus humain, pour un·e enseignant·e, que de « saquer » une élève jugée « trop sûre d’elle pour son propre bien » car elle a d’excellentes notes dans d’autres disciplines, ou encore un étudiant dont les options politiques ou syndicales déplaisent ? Quoi de plus humain que de noter favorablement, même inconsciemment, un élève que l’on juge agréable ? Quoi de plus humain, pour des étudiants s’estimant mal notés, que de soupçonner l’existence de favoritisme ou de discrimination ?

Pour toutes ces raisons, on a très largement adopté dans l’enseignement supérieur, les examens et les concours, la correction sur copies anonymes. Pourtant, n’est-il pas déshumanisant de remplacer le nom de l’étudiant par un numéro d’ordre ?

Ainsi, ce qui est plus humain, au sens d’une plus grande intervention des sentiments et jugements humains, n’est pas forcément plus juste ou meilleur… ni même d’ailleurs plus humain au sens de respectueux de la dignité humaine.

Quant à ParcourSup, on soutient parfois qu’il s’agit d’un processus plus humain que l’algorithme APB parce qu’il pose des questions successives aux candidats au lieu de les affecter à la suite d’un calcul à partir de l’ordre de leurs préférences. Là encore, on semble considérer qu’il est meilleur d’impliquer l’humain à chaque étape plutôt que de lui demander de se fier au résultat ultime d’un calcul qu’il n’effectue pas lui-même. Attitude curieuse ! Comme si une moyenne de notes calculée à la main était plus humaine qu’une moyenne calculée à l’aide d’un tableur. De fait, l’allongement de la durée du processus due à l’attente des réponses des candidats, bref de leur facteur humain, conduit à une attente et une angoisse que certains jugent inhumaine.

Ainsi, cet argument de l’humanité du nouveau processus confond plusieurs sens de « humain » : « Qui appartient à l'homme, qui lui est propre » (on demande une intervention du candidat à chaque étape », « Qui épouse pleinement la nature humaine dans ses qualités et ses défauts » (y compris la subjectivité de son jugement), et « Qui est sensible à la pitié, qui fait preuve d'indulgence, de compréhension envers les autres hommes ». C’est ainsi qu’avec un processus humain selon les deux premiers sens celui-ci peut s’avérer inhumain au sens du troisième.

samedi, mars 17 2018

Ma gestion des conflits d'intérêts

Dans la recherche scientifique, nous avons souvent à nous préoccuper de conflits d’intérêts. On pense évidemment à ceux des chercheurs qui travaillent sur un sujet tel que les produits pharmaceutiques, les pesticides, etc., où il y aurait intérêt à biaiser les résultats des études en faveur de tel ou tel industriel qui financerait les recherches, ou emploierait par ailleurs le chercheur comme consultant (on en trouve facilement des exemples dans l’actualité). Dans mon domaine de recherche, ces problèmes ne se posent guère. En revanche, se pose souvent le problème des conflits d’intérêts lorsqu’il s’agit d’évaluer leurs collègues ou leurs travaux.

Les travaux scientifiques sont évalués avant leur publication en revues, comptes-rendus de conférence, ou ouvrages, du moins chez les éditeurs scientifiques sérieux : le travail répond-il aux standards de qualité de sa discipline ? Quant aux scientifiques (au sens large, j’inclus les universitaires de toute discipline), ils sont évalués, à divers points de leur carrière. Les évaluateurs sont, habituellement, des scientifiques plus ou moins du même domaine (pour évaluer une publication très technique, on prendra des spécialistes, alors que pour évaluer une carrière on pourra prendre des évaluateurs plus loin thématiquement). Fatalement, ces évaluateurs connaissent parfois les auteurs des articles, les candidats aux promotions. Certains critiquent d’ailleurs un fonctionnement « par cooptation » ; mais il est difficile de faire autrement : pour évaluer quelqu’un pour un poste en France, avec un dossier en français et dans le contexte particulier de l’enseignement supérieur et la recherche français, en général il faut un français du même domaine, qui n’est pas si vaste.

Il se pose donc des conflits d’intérêts. Voici donc comment je gère ceux-ci quand c’est moi l’évaluateur.

Le malaise

Il m’est arrivé que l’on me demande de rédiger un rapport sur le dossier d’une personne que j’apprécie beaucoup. Je ne rentrais dans aucune des conditions que l’organisme commanditaire de l’évaluation considérait comme constituant un conflit d’intérêts, et pourtant je me sentais mal à l’aise. Je fis ce travail mais in fine j’aurais préféré que cela fût quelqu’un d’autre.

Premier critère pour moi : je peux refuser une évaluation, même si je ne rentre dans aucun cas officiel de conflit d’intérêts, si celle-ci me met mal à l’aise d’une façon ou d’une autre.

(Par ailleurs, je me suis retrouvé à devoir donner mon avis sur la candidature de quelqu’un dont j’appréciais humainement la compagnie, mais dont la compétence ne me paraissait pas suffisante pour le poste. Cette personne, l’ayant appris, m’en a par la suite durablement voulu. Ce genre de problèmes est également à prendre en compte.)

L’apparence du favoritisme

Imaginons que j’évalue un dossier sans éprouver d’inconfort en le faisant, que je ne rentre dans aucun des cas de conflit d’intérêts identifiés par le commanditaire de l’évaluation. Je risque cependant, dans certains cas, que certains se fassent la réflexion que j’aurais agi par favoritisme ou, au contraire, inimité, s’il y avait entre moi et la personne à évaluer des liens, réels ou supposés, positifs ou négatifs, remettant en cause mon objectivité.

Second critère : éviter ce qui pourrait donner lieu à mauvaise interprétation.

Les critères du commanditaire

Certains commanditaires d’évaluation ont une liste officielle de critères signalant un conflit d’intérêt (par exemple, avoir été directeur de thèse du candidat, avoir co-signé une publication avec lui pendant les 3 dernières années...) ; d’autres non. Dans tous les cas, si j’estime avoir un conflit d’intérêts (réel ou potentiel), j’explique les faits au commanditaire et je le laisse estimer si ceux-ci constituent ou non un conflit d’intérêts en son sens. En effet, je n’ai pas à me substituer à lui en ce qui concerne la politique de son organisme, de son éditeur, de sa revue…

Ainsi, dans ce domaine comme dans d’autres, je sépare bien ce qui relève d’une éthique personnelle (qui, en l’espèce, relève plus du désir d’éviter des situations inconfortables que d’un questionnement purement moral) de ce qui relève d’une question de politique des organismes ou des publications, où je laisse la décision à ceux qui en ont la responsabilité.

samedi, janvier 20 2018

Sur la portée des attaques SPECTRE et MELTDOWN

Les attaques Meltdown et Spectre ont beaucoup inquiété. Devant certaines questions, il me semble pertinent de préciser certains points.

Ces attaques visent à faire fuir des informations depuis un logiciel attaqué vers un logiciel attaquant, ce dernier devant réaliser un certain nombre d’actions très spécifiques pour obtenir, indirectement, des informations censément secrètes. Elles s’appuient sur des chronométrages fins de certaines opérations très particulières, le temps nécessaire à les réaliser variant suivant la valeur des données secrètes. Elles contournent ainsi les mécanismes de protection qui permettent à une même machine de faire fonctionner séparément les programmes de plusieurs utilisateurs.

Ces attaques sont donc importantes pour les prestataires de services d’hébergement cloud, qui louent à des utilisateurs la possibilité de lancer des logiciels sur des machines (dites « serveurs ») puissantes et situées dans des locaux adaptés (data centers), avec des connexions Internet à haut débit et faible latence et des assurances de fonctionnement en continu (personnel de permanence, onduleurs en cas de coupure de courant). Elles sont également importantes pour les entreprises et organismes qui ont des serveurs où un grand nombre d’utilisateurs peuvent lancer des logiciels de leur choix ; par exemple, pour les universités, certains étudiants ayant à cœur de vouloir contourner les mécanismes de sécurité.

Qu’en est-il des utilisateurs individuels ? Une personne qui utilise seule sa propre machine ne va évidemment pas essayer de se pirater elle-même. On pourrait éventuellement envisager une attaque en escalade : tout d’abord, les intrus se rendraient maîtres d’un logiciel peu privilégié (n’ayant pas accès aux donnés de l’utilisateur humain de la machine) mais communiquant en réseau, puis à partir de là essaieraient d’obtenir les données de l’utilisateur ; mais cela semble assez difficile (il y a probablement d’autres failles plus faciles à exploiter).

Le cas qui me paraît le plus réaliste est celui des navigateurs Web, qui font fonctionner des logiciels venant de l’extérieur (principalement écrits en langage Javascript). Pour être exécuté efficacement, le Javascript est traduit (on dit « compilé ») en instructions directement exécutables par l’ordinateur. Il semble possible d’écrire du Javascript tel qu’avec certains navigateurs le produit de cette traduction puisse être utilisé pour réaliser les chronométrages permettant l’attaque. Parmi les contre-mesures discutées, il y a la détection, lors des processus de compilation, de configurations vulnérables à l’attaque Spectre (ou de configurations attaquantes) et l’ajout d’instructions empêchant la fuite d’informations.

On m’a évoqué le cas des processeurs ARM ou STMicro. Ceux-ci ne sont pas utilisés dans des ordinateurs personnels ou dans des serveurs classiques, mais plutôt dans des objets connectés ou non ou des terminaux mobiles (téléphones, tablettes…). C’est un univers vaste et il faut distinguer plusieurs cas.

Les attaques Spectre et Meltdown visent à contourner des mécanismes de protection et d’isolation de processus les uns et des autres. Elles n’ont donc aucun intérêt sur des processeurs simples n’ayant pas de tels mécanismes de protection, où chaque logiciel a accès à la mémoire de tous les autres (ce qui a d’ailleurs été longtemps le cas sur les ordinateurs personnels).

Ces attaques s’appuient sur des mécanismes (mémoires caches, exécution spéculative…) qui n’existent que dans les processeurs à hautes performances, notamment ceux que l’on met dans les ordinateurs personnels et les serveurs. Les processeurs plus simples n’utilisant pas de tels mécanismes ne sont pas vulnérables.

Ces attaques supposent que l’on puisse charger un logiciel intrus, donc qu’il soit possible de charger des logiciels nouveau sans que ceux-ci n’aient à être authentifiés par le fabricant de l’objet. Les objets n’ayant pas la possibilité de charger des nouveaux logiciels, ou qui restreignent ce chargement à des logiciels produits par le fabricant de l’objet ou du moins validés par lui, avec au moment du chargement vérification de ce fait (signature électronique), ne sont donc pas concernés.

mardi, janvier 9 2018

Retour sur quelques questions sur MELTDOWN et SPECTRE

Suite à la publication de mes billets précédents sur les failles MELTDOWN et SPECTRE, j’ai répondu à diverses questions, et je pense que certaines méritent une réponse publique.

Les attaques par canaux cachés n’ont rien de nouveau

Un de mes interlocuteurs pensait que ces failles étaient les premières failles de sécurité basées sur un problème dans le matériel. Ce n’est pas le cas — peut-être serait-il en revanche exact que ce sont les premières failles de sécurité basées sur un problème dans le matériel qui soient venues à l’attention des journalistes.

Les failles MELTDOWN et SPECTRE s’appuient sur l’exploitation de « canaux cachés » permettant de transmettre de façon indirecte des informations d’un logiciel privilégié (au sens qu’il a accès à des informations sensibles) vers un logiciel intrus, ces canaux de communication découlant de certaines fonctionnalités du matériel (mémoires caches, notamment). Les attaques par canaux cachés n’ont rien de nouveau.

Une attaque par canal caché tend à recouvrer des informations secrètes en exploitant des effets indirects de l’exécution du programme manipulant ces données. Par exemple, dans le cas de cartes à puce contenant des clefs cryptographiques secrètes et qui doivent le rester, on a appliqué des attaques consistant à mesurer finement la consommation électrique instantanée de la carte à puce ou son rayonnement électromagnétique. Dans le cas de logiciels sensibles s’exécutant sur la même machine que des logiciels malveillants (cas réaliste par exemple dans le cas de cloud computing, où des applications de plusieurs clients fonctionnent sur le même serveur), le logiciel malveillant peut notamment observer de petites fluctuations de son temps d’exécution dues à l’activité du logiciel sensible. Je n’ai pas le temps ce soir de rechercher les premières propositions de ce type d’attaques, mais je relève notamment l’attaque de Daniel J. Bernstein en 2005 contre des logiciels implantant le standard de chiffrement AES.

Ce type d’attaques est maintenant tellement représenté dans la littérature scientifique et technique que certains logiciels sont « durcis » pour éviter de laisser prise à ces observations exploitant l’isolation imparfaite fournie par les processeurs. Par exemple, pour éviter que des mesures fines du temps qu’un logiciel met à chiffrer des données ne soient exploitées pour retirer des informations sur les clefs cryptographiques, on mettra en œuvre du chiffrement en temps constant. Pour éviter que des informations ne fuient par les caches (je ne vais pas expliquer en quoi cela consiste, c’est assez technique), on va programmer les logiciels d’une façon à ne pas avoir d’action sur le cache qui permette de dériver des informations sur les données secrètes. D’ailleurs, un des buts d’une thèse que je dirige, celle de Valentin Touzeau, est d’analyser les logiciels pour détecter de telles vulnérabilités.

Il y a déjà eu des trous de sécurité importants dans le matériel, y compris d’Intel

Certains matériels Intel contiennent, en sus du processeur principal, un processeur auxiliaire nommé « moteur de gestion », caché du système d’exploitation installé sur le processeur principal et comportant son propre système d’exploitation et logiciels. En 2017 il a été révélé que ce moteur de gestion était vulnérable à des attaques.

Ce n’est pas la première fois qu’il y a des trous de sécurité importants nécessitant des mises à jour massives chez les prestataires d’hébergement

Je ne vais pas refaire l’historique de tous les trous de sécurité trouvés dans les logiciels utilisés chez les hébergeurs et me contenterai de mentionner le fait suivant. En 2008, donc à une époque où les services en ligne étaient déjà bien développés, avec beaucoup d’informations personnelles stockées chez des prestataires, on s’est aperçu que le générateur de clefs cryptographiques SSH et SSL livré notamment dans les distributions Linux Debian et Ubuntu avait été modifié, apparemment par erreur naïve et non par malice, de sorte que toutes les clefs générées étaient vulnérables. Cela voulait dire que des gens malveillants pouvaient se faire passer auprès de divers systèmes pour des utilisateurs ou administrateurs légitimes, ou encore intercepter des communications Web réputées sécurisées (le fameux logo cadenas) en se faisant passer pour un site légitime et récupérer toutes les informations secrètes transmises (mots de passe, y compris bancaires, etc.).

Malgré l’importance et la stupidité de ce bug, qui a nécessité une mise à jour d’urgence dans un très grand nombre de systèmes (y compris des systèmes non basés sur Debian ou Ubuntu, puisque ce qui compte c’est la machine qui avait généré les clefs), la presse grand-public n’en a pas parlé.

Il existe de la recherche universitaire en sécurité informatique

Il existe dans les universités, ou des organismes tels que le CNRS ou l’INRIA, de la recherche en sécurité informatique. Celle-ci n’est l’apanage ni des entreprises privées telles que Google, ni des organismes très orientés applications industrielles tels que le CEA, ni des services gouvernementaux spécialisés comme l’ANSSI ou la DGA-MI. D’ailleurs, les vulnérabilités MELTDOWN et SPECTRE ont été découvertes conjointement par des chercheurs de l’université technique de Graz, en Autriche, et une jeune chercheuse de cette équipe a rejoint le CNRS l’an dernier.

Ce qui est en revanche exact, c’est que les entreprises comme Google, Amazon, Facebook ou Microsoft ont des moyens sans commune mesure avec les laboratoires universitaires. Ainsi, il y a quelques années, j’ai vu un collègue recruter pour une des équipes de sécurité chez Google ; il « faisait son marché », envisageait de débaucher des universitaires (dont moi), etc., avec un budget pour 20 personnes. Par comparaison, le CNRS, tous laboratoires confondus, recrute cette année, est c’est exceptionnellement généreux, 2 jeunes chercheurs en sécurité informatique.

Où est la nouveauté ?

La nouveauté consiste en l’utilisation active de l’exécution spéculative des processeurs à hautes performances, conjointement aux canaux cachés.

Quel impact ?

À lire certains, la vulnérabilité MELTDOWN aurait permis de lire à volonté n’importe quelle portion de la mémoire de la machine attaquée. Or, après lecture plus approfondie des documents publiés par Intel et Google, on s’aperçoit que les données attaquables sont celles résidant en mémoire cache de niveau 1 au moment de l’attaque, ce qui est une infime portion de la mémoire de la machine. Un des codes de démonstration de la faille qui circule publiquement fait juste avant l’attaque un appel au système qui a pour effet secondaire de charger dans le cache de niveau 1 des informations qu’il va ensuite lire via MELTDOWN ; ce code de démonstration se contente cependant de provoquer le chargement de données absolument pas sensibles. Il n’est pas évident pour moi qu’il soit possible de forcer le système d’exploitation à manipuler des données sensibles de façon à ce qu’elles soient disponibles en cache de niveau 1 au moment de l’attaque (il est cependant possible qu’il y ait un autre volet de l’attaque qui n’ait pas encore été rendu public au 8 janvier et que la présence dans le cache L1 ne soit pas nécessaire).

En l’état de mes informations, je ne comprends donc pas trop l’urgence qu’il y a à mettre en œuvre des contre-mesures, éventuellement mal maîtrisées ou occasionnant des pertes notables de performance, contre l’attaque MELTDOWN.

J’insiste cependant que je ne suis pas un expert en sécurité informatique de bas niveau, et que je n’ai accès à aucune information secrète.

En revanche, les attaques MELTDOWN et SPECTRE m’inquiètent en ce qu’elles démontrent que les processeurs actuels, avec leurs nombreux dispositifs destinés à augmenter les performances, notamment les mémoires cache et l’exécution spéculative, sont devenus d’une telle complexité qu’il existe des interactions insoupçonnées des créateurs de ces systèmes. La compartimentation proposée par ces processeurs est très imparfaite et il est difficile de penser à tous les biais possibles d’attaque. On peut également se poser des questions sur le modèle de sécurité basé sur la séparation mémoire matérielle entre processus, et des processus entre utilisateurs : est-il adapté à une époque où le navigateur Web exécute des logiciels de toute provenance à l’aide de mécanismes complexes et donc potentiellement vulnérables ? Je n’ai évidemment pas de réponse à ces questions.

PS: L'hyperthreading peut sans doute aussi aboutir à ce que certaines données sensibles soient chargées en cache...

lundi, janvier 8 2018

MELTDOWN wonderment

It seems that the Meltdown leak only happens if (kernel) data is in the L1 cache.

This seems like an onerous restriction on applicability of the attack : it is like one would have to make a system call to the kernel which would read the secret data just prior to the attack.

This is a far cry from the first comments on the issue, which implied that any memory accessible by the kernel (thus, in Linux and MacOS X at least, all of physical RAM) was readable.

Or is there something not yet public ?

samedi, janvier 6 2018

MELTDOWN implemented

I now have a working implementation of the MELTDOWN attack, which I developed in about one day after reading the Lipp et al. paper. It is not pretty; the one from Pavel Boldin is much more complete.

I got stuck for hours, not understanding why I could not transfer information depending on secret data through the side channel, until I read Pavel Boldin’s implementation and realized that just before conducting the attack, he made a system call that made the kernel read the secret data under attack (as an example, he read from /proc/version, which makes the kernel read from a format string known as linux_proc_banner, and then checked that he could that format string from the supposedly protected kernel memory).

I suppose that the reason is that this loads the string into some of the CPU caches, which would imply that the MELTDOWN attack only works for data that is already in some of these caches. I suppose that if a cache reload of the secret data is needed, then the protection check will be performed before the speculative loads are performed.

I am unsure whether there is a method to force the cache loading of arbitrary protected memory locations.

I also have a working implementation for breaking kernel address space layout randomization (KASLR). I simply implemented the ideas from Jang et al., Breaking Kernel Address Space Layout Randomization with Intel TSX: namely, it takes fewer CPU cycles to generate a protection fault against a mapped, but protected, page, than for unmapped space; in both cases this generates a segmentation violation, but no trap is generated if the illegal accessed is wrapped in a transaction (Restricted Transactional Memory). It is sufficient to measure the time taken to complete the transaction, on my machine it is about 186 cycles when mapped versus 200+ cycles when unmapped.

PS: My idea about the data needing to be inside a close cache is confirmed by Intel's analysis:

For instance, on some implementations such a speculative operation will only pass data on to subsequent operations if the data is resident in the lowest level data cache (L1). This can allow the data in question to be queried by the application, leading to a side channel that reveals supervisor data.


vendredi, janvier 5 2018

Pourquoi l'informatique devient incompréhensible, et l'impact sur la sécurité

Les failles de sécurité SPECTRE et MELTDOWN sont, comme je l’ai expliqué dans des billets précédents, des attaques par canaux cachés. Il me semble pertinent de prendre ici un peu de recul sur ces questions ; je n’aurai pas la prétention de dire qu’il s’agit de philosopher, mais c’est un peu l’idée.

Grosso modo, quand on programme, on décrit une suite d’opérations à exécuter par la machine pour obtenir le résultat désiré. Le sens, on dit aussi la sémantique, de ces opérations est documenté, que l’on programme dans un langage de programmation de haut niveau (Python, C++, Prolog…) ou en langage machine (Intel x86…). Plus précisément, ce qui est documenté c’est la sémantique fonctionnelle, c’est-à-dire le résultat des opérations (par exemple, l’opération d’addition réalise une addition, sous réserve que le résultat ne dépasse pas un certain nombre de chiffres, etc.). Il existe en revanche diverses propriétés non fonctionnelles peu documentées et souvent difficilement prévisibles : le temps de calcul, la consommation électrique, etc. Naturellement, il est bien plus facile de raisonner sur les propriétés fonctionnelles que sur les propriétés non fonctionnelles.

Les mécanismes de sécurité incorporés aux langages, processeurs et systèmes d’exploitation modernes visent les propriétés fonctionnelles : notamment lorsqu’un programme tente d’accéder à des données auxquelles il n’a pas accès, cet accès est refusé. On peut ainsi isoler les uns des autres différents programmes, différents utilisateurs.

Il est toutefois bien plus difficile d’isoler les aspects non fonctionnels. Par exemple, si je lance un logiciel sur une machine, même si je n’ai pas officiellement le droit de lire la table des logiciels lancés par d’autres utilisateurs, je peux savoir qu’un autre logiciel est lancé si le mien est ralenti. Par des mesures plus fines, je peux même éventuellement me douter de ce qu’il fait : par exemple, s’il est dans une phase de calcul intensif sans grands accès à la mémoire principale, mes accès à la mémoire principale ne seront guère ralentis, tandis que s’il fait beaucoup d’accès, il ralentira les miens. D’une façon générale, plus il y a de ressources partagées (temps de calcul, mémoire, etc.) entre plusieurs utilisations, plus il y a la possibilité de passer des informations via des propriétés non fonctionnelles entre des domaines qui, a priori, sont fonctionnellement isolés. On appelle cela des canaux cachés.

Il y a maintes façons d’utiliser les canaux cachés. Par exemple, si on a la possibilité de faire fonctionner, sur la même machine, un logiciel qui a accès à une base de données sensibles mais n’a pas accès aux communications réseau et un logiciel qui n’a pas accès à la base de données et a accès aux communications réseau, séparés fonctionnellement (pas de canal de communication officiel entre les deux), on pourra transmettre des informations de l’un à l’autre par un canal caché (par exemple, mais il existe bien évidemment des méthodes plus efficaces, en alternant des périodes d’accès mémoire intensifs et faibles en une sorte de code Morse). La nouveauté des attaques MELTDOWN et SPECTRE est qu’il est possible de faire exécuter à un logiciel disposant d’accès privilégié aux données des instructions qu’il ne devrait pas vraiment exécuter, et qui n’ont d’ailleurs pas d’effet fonctionnel, mais conservent leurs effets non fonctionnels. Ce qui permet à ces attaques de fonctionner, c’est que diverses ressources matérielles (et notamment des mémoires cache) sont partagées entre des logiciels privilégiés (noyau du système d’exploitation, navigateur Web…) et non privilégiés (simple application, code Javascript d’une page Web…).

La complexité des machines actuelles, due à la recherche de hautes performance, avec la présence de nombreuses ressources partagées, est telle qu’il est difficile d’éviter les canaux cachés. Elle rend également difficile de démontrer quoi que ce soit de précis sur les propriétés non fonctionnelles, notamment le temps d’exécution. C’est un problème qui concerne notamment ceux qui veulent produire des dispositifs matériels répondant sous un certain délai garanti, par exemple des systèmes qui contrôlent des avions : comment, dans un système mettant en jeu plusieurs cœurs de processeur partageant de la mémoire, chacun avec des mémoires cache compliquées, garantir que l’exécution d’un programme prendra moins d’un centième de seconde dans tous les cas ? Nous sommes loin de ces processeurs des années 1980 dont la documentation donnait le temps d’exécution de chaque instruction...

Si l’on peut résumer une bonne partie de l’informatique depuis 70 ans, tant côté logiciel que matériel, on a progressivement éloigné le programmeur de l’exécution physique sur la machine, en rajoutant de plus en plus de couches de traduction, d’émulation, de virtualisation… Il y a d’excellentes raisons à cela : il est bon que le programmeur n’ait pas à se préoccuper des détails matériels de chaque machine, au risque que son programme ne fonctionne plus sur le modèle sorti un an après ; on peut mutualiser des ressources (dans un avion ou une voiture, mettre plusieurs tâches sur le même calculateur au lieu de mettre plusieurs calculateurs ; dans le cloud, mettre plusieurs utilisateurs indépendants sur le même serveur…). Cet éloignement nous empêche toutefois de bien appréhender les canaux cachés et propriétés non fonctionnelles.

Plus généralement, on a assisté à une bureaucratisation de la programmation. Sur un ordinateur personnel des années 1980, si l’on voulait dessiner une forme dans l’écran, il suffisait, au pire, d’aller écrire les valeurs des couleurs désirées dans la mémoire destinée à l’affichage vidéo : on voulait du bleu, on écrivait un code dans une case mémoire et on avait du bleu. Maintenant, il faut en quelque sorte remplir une série de formulaires administratifs pour avoir le droit de demander à un autre logiciel d’allumer le point. C’est la différence entre faire des travaux soi-même chez soi et demander au service de l’entretien d’envoyer un ouvrier les faire… Dans le premier cas, on maîtrise évidemment mieux ce qui est effectivement fait.

L'attaque MELTDOWN

Les réseaux sociaux et les blogs spécialisés en sécurité bruissaient de rumeurs depuis une semaine (pourquoi des modifications si urgentes dans le système de gestion de mémoire du noyau Linux, alors que d’habitude il faut des mois et des mois pour que le moindre changement soit accepté ?). Comme d’habitude lorsque des trous de sécurité majeurs sont découverts, ceux-ci n’étaient documentés que sous embargo, c’est-à-dire qu’on a d’abord informé les industriels ou groupes de développeurs susceptibles de fournir des correctifs, en leur laissant un délai suffisant, avant de publier les articles décrivant les problèmes.

Il y a en fait deux catégories d’attaques publiées ce jour : MELTDOWN et SPECTRE, qui partagent certaines caractéristiques. J’ai publié un autre billet sur SPECTRE, dont je vais reprendre ici quelques éléments explicatifs. Je vais discuter ici de MELTDOWN, en me basant sur la lecture de l’article décrivant les attaques (Lipp et al., Meltdown). Les attaques MELTDOWN sont celles contre lesquelles Microsoft, Apple et les développeurs de Linux ont intégré des contre-mesures. Je vais tenter de les expliquer à un niveau ne nécessitant pas de connaissances particulières en informatique.

Lire la suite...

jeudi, janvier 4 2018

L'attaque SPECTRE

Les réseaux sociaux et les blogs spécialisés en sécurité bruissaient de rumeurs depuis une semaine (pourquoi des modifications si urgentes dans le système de gestion de mémoire du noyau Linux, alors que d’habitude il faut des mois et des mois pour que le moindre changement soit accepté ?). Comme d’habitude lorsque des trous de sécurité majeurs sont découverts, ceux-ci n’étaient documentés que sous embargo, c’est-à-dire qu’on a d’abord informé les industriels ou groupes de développeurs susceptibles de fournir des correctifs, en leur laissant un délai suffisant, avant de publier les articles décrivant les problèmes.
Il y a en fait deux catégories d’attaques publiées ce jour : MELTDOWN et SPECTRE. Les attaques MELTDOWN sont celles contre lesquelles Microsoft, Apple et les développeurs de Linux ont intégré des contre-mesures. Je vais ici discuter des attaques SPECTRE, contre lesquelles il n’y a, à ma connaissance, pas de contre-mesure. Je me base pour cela sur la lecture de l’article décrivant les attaques (Kocher et al., Spectre Attacks: Exploiting Speculative Execution), article très pédagogique au moins au début. Je vais tenter de les expliquer à un niveau ne nécessitant pas de connaissances particulières en informatique.

Lire la suite...

samedi, décembre 2 2017

Quelques remarques sur l'apocalypse logicielle à venir

J’ai eu l’agréable surprise de trouver dans The Atlantic, magazine grand public, un article sur des thèmes proches de ceux de certaines de mes recherches, qui plus est, ce qui est surprenant pour un magazine américain, avec des mentions de technologies informatiques françaises. J’ai plus de réserves, en revanche, sur le titre (The coming software apocalypse) et ce qui était visiblement un titre de travail (Saving the world from code).

Il me semble que la courte histoire de l’informatique est jalonnée d’articles (dans des revues plus spécialisées) expliquant que les façons de programmer les plus répandues ne pourraient plus durer et qu’il faudrait passer à d’autres approches, naturellement celles promues par la personne qui a rédigé l’article ou les personnes interrogées, suivis d’articles disant le contraire. Je ne retrouve hélas pas les références, mais je me souviens d’articles des années 1970 qui disaient le premier qu’il faut passer aux « méthodes formelles » pour raisonner sur les programmes et ainsi éviter les bugs, le second que ces méthodes formelles ne fonctionnent que sur de petits exemples jouets et ne sont pas adaptés à l’immense majorité des développements logiciels. Ceci devrait nous rassurer sur l’apocalypse à venir : d’autres apocalypses étaient déjà annoncées et ont été surmontées !

Passons maintenant au fond. On peut définir la programmation informatique comme l’activité de passer de la spécification de ce qu’un logiciel devrait faire à un programme effectivement exécutable par un ordinateur, comprenant une phase d’analyse (décomposition du problème en sous-problèmes jusqu’à ce que ceux-ci deviennent traitables par une machine) et une phase de programmation proprement dite, c’est-à-dire le passage d’idées abstraites (algorithmes, structures de données, interactions entre composants…) à un programme. (Ces deux phases ne se succèdent pas forcément dans le temps : on peut commencer de développer le logiciel, avoir un fonctionnement partiel, analyser ce qui manque, le programmer, etc.) La difficulté de la programmation, c’est l’éloignement entre la spécification et ce que la machine sait effectivement faire.

Dans sa forme la plus primitive, la programmation consiste à produire une suite d’instructions en langage machine, c’est-à-dire des codes numériques correspondant à des opérations à faire exécuter (par exemple, il existe un code pour demander une addition). C’est extrêmement fastidieux (il faut non seulement coder les instructions mais aussi se souvenir de numéros désignant les endroits où l’on a stocké les données) tout en nécessitant une grande minutie. Un premier progrès a été la possibilité de programmer en langage d’assemblage, c’est-à-dire en écrivant les noms des instructions (par exemple « add a,5 » pour demander d’ajouter 5 au registre a) et en laissant un logiciel, l’assembleur, calculer tout seul les numéros des stockages de données. Toutefois, cela revenait encore à descendre à un grand niveau de détail technique pour exprimer ce que l’on voulait faire.

On a donc proposé des langages de programmation de plus haut niveau que le langage d’assemblage, en premier lieu Fortran, dont le nom est juste la contraction de l’anglais pour « traducteur de formules ». On écrivait des programmes décrivant des procédures de calcul (pour la physique, l’artillerie, etc.) dans un format textuel assez lisible (par exemple, pour dire que a prend la valeur de trois fois b plus un, on écrivait a=3*b+1, il y avait des ordres pour dire de répéter une séquence d’instructions un certain nombre de fois) et un logiciel appelé compilateur traduisait en langage machine. La productivité des programmeurs était considérablement augmentée : on éliminait l’étape fastidieuse de codage vers le langage d’assemblage voire le langage machine, et les bugs que celle-ci pouvait introduire (bien entendu, à supposer que le compilateur lui-même ne contienne pas de bugs). Il me semble même avoir lu que certains disaient que cela éliminerait les bugs ! Hélas, il restait évidemment les bugs de plus haut niveau : ceux dans l’enchaînement des instructions à répéter, les formules etc. (et éventuellement des fautes d’inattention dans l’écriture du Fortran).

D’une façon générale, l’évolution des langages de programmation, depuis l’époque lointaine du premier Fortran, a tendu vers plus d’expressivité : permettre aux programmeurs d’exprimer ce qu’ils veulent voir exécuté sous une forme plus proche de ce qu’ils ont à l’esprit et avec moins de détails propres au fonctionnement de la machine. Cette évolution a porté tant sur la phase d’analyse que sur celle de programmation. Pour la programmation, il s’agit de pouvoir écrire d’une façon simple des directives qui seront transformées par le compilateur en des suites d’instructions complexes. Pour l’analyse, il s’agit de la fourniture de bibliothèques d’algorithmes et de structures de données déjà prêtes, souvent conçues par des programmeurs plus experts que le programmeur qui les utilisent, et qui lui évitent donc de « réinventer la roue ».

La proposition de l’article d’en venir à une programmation basée sur les modèles est donc une évolution naturelle. Les concepteurs de systèmes automatiques de contrôle (par exemple, de pilotage d’avion) raisonnent en termes de traitement du signal : prendre la mesure d’un capteur, éliminer les variations trop rapides (des parasites), détecter quand il dépasse un certain seuil…, opérations qu’ils représentent à l’aide de boîtes reliées par des fils, par analogie avec les vraies connexions électriques, lorsque chacune de ces boîtes était mise en œuvre par un composant électronique. C’est ce que proposent par exemple Scade, cité dans l’article, ou encore Simulink. Cette représentation est plus visuelle et intelligible pour les ingénieurs automaticiens que la mise en œuvre de ce traitement du signal dans un langage tel que C ou Fortran.

Une représentation de haut niveau, proche du concept que veulent mettre en œuvre les programmeurs, peut permettre par ailleurs la mise en œuvre d’aides au développement, — notamment, dans le cas de l’automatique, des simulations de la chaîne de traitement du signal sur des signaux représentatifs du système physique (par exemple, capteurs et actionneurs d’une aile d’avion), afin de se rendre compte si elle a les propriétés attendues (comme dans Simulink). L’exemple du début de l’article relève de la même idée : plutôt que de demander au programmeur de fixer des coefficients numériques par essai et erreur, on va lui fournir une visualisation instantanée qui lui permettra de les régler.

Toutefois, contrairement à ce que laisse supposer l’article, l’utilisation de tels langages graphiques ne supprime pas les bugs. Prenons le cas de la commande de vol électrique d’un avion de ligne. On va la concevoir graphiquement, à l’aide d’outils adaptés aux représentations des automaticiens spécialistes d’avionique et de contrôle aéronautique, puis (je simplifie) la transformer automatiquement en un logiciel que l’on peut effectivement embarquer dans l’avion. Cette transformation automatique sera à la fois plus fiable et moins coûteuse en personnel qu’une programmation manuelle. Rien ne nous dit toutefois que les lois d’automatique et les dispositifs de protection contre les erreurs et pannes décrits dans la représentation graphique suffisent à garantir la véritable spécification, à savoir « l’avion vole correctement » !

Par ailleurs, pour chaque représentation plus proche des préoccupations du développeur, il faut développer des outils ad hoc. On peut avoir un Scade, un Simulink, pour toutes les applications d’automatique, mais on peut difficilement, pour chaque problème spécialisé, développer un outil destiné à mieux attaquer ce problème.

On entend actuellement en France un discours bien rôdé selon lequel nous ne formerions pas assez de développeurs, les formations des universités et écoles publiques étant inadaptées. Le très médiatique docteur en médecine Laurent Alexandre répond, lui, que de toute façon ces tâches de développement seront bientôt assumées par des intelligences artificielles et qu’il conviendrait donc plutôt de mettre l’accent sur les humanités. Je suis sceptique quant à cette affirmation, qui me semble reposer sur l’anticipation de progrès considérables en intelligence artificielle, dont nous n’avons aucune raison de penser qu’ils se produiront à l’échelle de quelques décennies. Par ailleurs, ce n’est pas la première fois que l’on annonce la fin de la programmation au sens courant du terme. Il me semble bien que l’on avait déjà annoncé dans les années 1980 le remplacement de celle-ci par la programmation logique concurrente et des intelligences artificielles, comme dans le projet japonais d’ordinateur de cinquième génération ; mais ce n’est pas ce qui s’est passé…


samedi, novembre 11 2017

L'enseignement très spécialisé est-il un modèle ?

Mon billet sur la publicité dont jouit l’école 42 et les remarques méprisantes que certains commentateurs font à l’égard de l’enseignement universitaire a suscité des réactions. Une intéressante discussion a pris place dans ses commentaires, et j’aimerais rebondir sur certaines réactions, notamment celles de Laurent Bloch et de Loys Bonod.

Dominique Seux remarquait

« Alors, évidemment, si on était caustique, on s’étonnerait que les milliers d’enseignants-chercheurs de nos grandes universités scientifiques n’aient pas eu l’idée de lancer des formations en développement informatique. »

Cette remarque, nous l’avons vu, est absurde, vu que justement il existe de telles formations au sein des universités. Toutefois, il est possible de la modifier pour lui donner du sens :

« Alors, évidemment, si on était caustique, on s’étonnerait que les milliers d’enseignants-chercheurs de nos grandes universités scientifiques n’aient pas eu l’idée de lancer des formations en développement informatique, centrées uniquement sur la programmation, à l’exclusion de toutes les autres questions informatiques, des autres disciplines scientifiques et de toute formation générale. »

En effet, il ne me semble pas qu’il existe dans les universités de formation ne comprenant que de la programmation, ni même, au moins au niveau de la première ou deuxième année après le baccalauréat, que de l’informatique.

Relevons tout d’abord que pareille hyperspécialisation irait à l’encontre de la politique annoncée par l’actuelle ministre de l’enseignement supérieur, qui prône des licences pluridisciplinaires avec spécialisation progressive (ce qui est d’ailleurs déjà le cas en sciences à Grenoble, par exemple).

Par ailleurs, rappelons que l’État réglemente les diplômes à validité nationale (licence, master…), que pour les diplômes universitaires de technologie il y a un programme national, que les universités traversent une mauvaise période financière, avec de grandes difficultés à assurer leurs fonctions de base, et que donc la liberté que les « milliers d’enseignants-chercheurs de nos grandes universités scientifiques » auraient de lancer de nouvelles formations atypiques est très limitée ; ce n’est pas simplement une question d’en avoir l’idée.

Laurent Bloch relève, à juste titre, que les formations d’informatique, au moins au début, sont souvent couplées avec des enseignements de mathématique et/ou de physique, qui peuvent rebuter les étudiants. Il souligne notamment qu’une grande partie des élèves sortent de l’enseignement secondaire en difficulté en mathématiques.

L’enseignement secondaire français, même lorsqu’il y a des filières, comprend un très large enseignement « général », allant du sport à la philosophie. Cet enseignement est obligatoire, quels que soient les goûts et aspirations des élèves, et l’utilité, éventuellement nulle, des disciplines enseignées pour leurs choix de carrière et la vie qu’ils envisagent. Il est courant que certaines de ces disciplines rebutent les élèves, qui ensuite en conçoivent un dégoût marqué et ne veulent plus les retrouver dans l’enseignement supérieur. C’est donc une question qui dépasse largement les mathématiques et la formation des « développeurs ».

Voyons toutefois le cas particulier de l’enseignement de l’informatique. Il est possible de se focaliser sur la programmation (éventuellement en se spécialisant sur tel ou tel langage, telle ou telle technologie Web, etc.) et d’ignorer tout le reste. L’inconvénient d’une telle formation est qu’elle mentionnerait des outils sans pour autant expliquer comment ceux-ci fonctionnent, alors que souvent, en informatique, il faut avoir une certaine connaissance (non détaillée) du fonctionnement interne des outils pour les utiliser efficacement. Par exemple (je m’excuse d’avance pour mes lecteurs non informaticiens si je deviens technique), les bibliothèques standard des langages de programmation modernes proposent des implantations efficaces des notions d’ensemble et de fonction à support fini, par arbres binaires, par tables de hachage, voire par liste ou tableau d’association. Chacun de ces cas correspond à certains usages, mais il est impossible de le savoir si on les utilise comme des « boîtes noires » sans chercher à comprendre leur fonctionnement. La conséquence probable d’une utilisation aveugle et « bricolée » sera un logiciel qui fonctionnera bien sur de petits jeux de données mais dont les performances se dégraderont très vite lorsque les données seront plus grandes. Il en est de même de la conception d’une base de données sans comprendre un peu le fonctionnement interne d’un moteur de bases de données.

En raison de cela, les formations classiques en informatique comprennent non seulement de la programmation, mais aussi de l’algorithmique et d’autres matières. Traditionnellement, l’enseignement de l’algorithmique s’appuie sur des démonstrations mathématiques, notamment des preuves par récurrence. De telles démonstrations passent au-dessus de la tête de bon nombre d’étudiants actuellement en informatique à l’université, et on leur substitue donc souvent des explications « avec les mains » (par exemple, on peut montrer la complexité en n log n du tri fusion par un petit dessin). De même, on peut expliquer les bases de données relationnelles avec des raisonnements ensemblistes, mais il est sans doute possible de limiter l’usage du vocabulaire mathématique. Il y a toutefois des limites qu’on ne peut pas dépasser en matière d’incompréhension mathématique sans entraîner l’incompréhension informatique.

On le voit, la question posée par 42 n’est pas seulement celle de l’école sans enseignant (il existe depuis longtemps des méthodes de langues, de musique etc. destinées à l’apprentissage sans enseignant, et personne ne s’en émeut). Elle est plutôt celle d’un apprentissage très étroit, produisant en quelque sorte des ouvriers du tertiaire avec peu de recul sur leur activité. Or, tandis que certains la couvrent de lauriers dans les médias, d’autres (voire parfois les mêmes) déplorent le « cloisonnement » des disciplines universitaires et des formations ; clairement les universitaires subissent des injonctions contradictoires !

mercredi, novembre 8 2017

Au sujet de l'école 42 et de la publicité dont elle bénéficie

Dominique Seux, chroniqueur aux Échos, a le lundi 6 novembre choisi d’évoquer la fameuse école 42 de Xavier Niel sur l’antenne de France Inter. Il a notamment déclaré :

« Alors, évidemment, si on était caustique, on s’étonnerait que les milliers d’enseignants-chercheurs de nos grandes universités scientifiques n’aient pas eu l’idée de lancer des formations en développement informatique. »

Si on était caustique à l’égard M. Seux, on relèverait que, justement, les enseignants-chercheurs des universités scientifiques ont lancé de telles formations depuis des décennies. Pour prendre des exemples locaux, l’École nationale supérieure d’informatique et de mathématiques appliquées de Grenoble (ENSIMAG) fut fondée en… 1960, le département informatique de l’institut universitaire de technologie (IUT) de Grenoble en 1966 ; les MIAGE (formations aux Méthodes informatiques appliquées à la gestion des entreprises) existent depuis 1969. Bref, rien de nouveau sous le soleil.

Puisque M. Seux évoque les « milliers d’enseignants-chercheurs de nos grandes universités scientifiques », rappelons qu’il y a de l’ordre de 3400 enseignants-chercheurs de statut universitaire en informatique. Je ne sais pas ce que M. Seux s’imagine qu’ils enseignent, peut-être de la théorie de haute volée ou de l’histoire de l’informatique ? Ce n’est pas le cas ! (Ou du moins, c’est très rarement le cas, évidemment à Normale Sup on peut se permettre de faire de la théorie de haute volée…) La grande majorité des enseignements portent sur ce que les étudiants doivent savoir pour occuper, plus tard, des emplois de développeur, administrateur système, etc.

Revenons sur 42. M. Seux indique (j’ignore si ces chiffres sont exacts) que cette école reçoit 50000 candidatures par an et n’en accepte que 900. C’est donc une école extrêmement sélective à l’entrée. Ensuite, si l’on en croit les informations diffusées par les médias, il y a une très forte pression de sélection interne (les étudiants qui n’arrivent pas à se débrouiller sont exclus). En résumé, il s’agit d’un enseignement (ou d’une absence d’enseignement) qui s’adresse à une très petite minorité.

Les universités, quant à elles, ont une mission d’enseignement très générale — on a beaucoup rappelé récemment qu’elles sont censées accepter tout bachelier (il existe également des voies d’accès sans baccalauréat). Il n’est pas clair que les méthodes « sans enseignants » qui conviennent à une infime minorité conviendraient au public de l’enseignement de masse. J’en doute même fortement. Je sais bien qu’il est tentant (on sent bien ce sous-entendu derrière le discours sur les milliers de fonctionnaires dont on se demande bien ce qu’ils font) de penser que l’on pourrait largement se passer de la masse salariale d’enseignants, mais tout ce qui est tentant n’est pas forcément possible.

Prenons un parallèle. Personne ne suggère que l’on supprime l’enseignement des mathématiques et qu’on le remplace par la mise à disposition de manuels et dispositifs informatiques. Pourtant, le grand mathématicien Srinivasa Ramanujan, lorsqu’il était adolescent, a en grande partie appris les mathématiques seul en s’aidant d’un ouvrage de synthèse. Imaginez les économies que l’on pourrait faire en se défaisant des professeurs de mathématiques de lycée !

Si j’évoque cette chronique, c’est parce que celle-ci s’inscrit dans tout un discours médiatique à l’égard de l’enseignement de l’informatique en France, où l’on oppose la modernité de l’école 42 aux pratiques supposées archaïques des universités, et où l’on vante l’enseignement privé. Pour ma part, j’ai un raisonnement simple : enseigner à une infime minorité sélectionnée est facile — je le sais, j’ai enseigné 13 ans à l’École polytechnique (*). La question difficile est celle de l’enseignement de masse, surtout si celui-ci doit déboucher sur des emplois (il me semble d’ailleurs que les diplômés d’informatique des universités n’ont en général aucun problème pour trouver un emploi). Pourquoi faut-il encore et encore rappeler pareilles évidences ?

(*) Et même à l'École polytechnique la grande majorité des enseignements d'informatique, en masse d'étudiants, portent sur les bases du développement de logiciels et non sur des aspects de haute volée.

- page 1 de 95