Blog Haypo

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

samedi 28 avril 2007

Photos Wikipédia : Noir et blanc

Sélection personnelle de photos Wikipédia faite à partir des images du jour d'avril 2007. Série « Noir et blanc ».

Je vous conseille vivement de cliquer sur chaque photo pour obtenir la description ainsi que la version haute résolution.

Photos Wikipédia : Métropoles

Sélection personnelle de photos Wikipédia faite à partir des images du jour d'avril 2007. Série « Métropoles ».

Je vous conseille vivement de cliquer sur chaque photo pour obtenir la description ainsi que la version haute résolution.

Photos Wikipédia : Vu du ciel

Sélection personnelle de photos Wikipédia faite à partir des images du jour d'avril 2007. Série « Vu du ciel ».

Je vous conseille vivement de cliquer sur chaque photo pour obtenir la description ainsi que la version haute résolution.

mardi 24 avril 2007

Imposer des limites arbitraires

Durant mes essais de fuzzing, j'ai compris assez vite qu'espérer écrire un programme parfait n'est qu'un idéal. Plutôt que de corriger les erreurs, je pense qu'il vaut mieux écrire du code tolérant aux erreurs. Je veux dire par là que le programme continuera à fonctionner même si une procédure échoue.

Utiliser les exceptions

On peut utiliser pour ça le couple try/except en Python. Exemple trivial :

value = (...)
try:
   print "Date : %s" % datetime.datetime.fromtimestamp(value)
except ValueError:
   print "Date invalide (%r) !" % value

Mais le fuzzing mène souvent à une situation d'épuisement (monopolisation) des ressources : votre programme va manger tout le temps processeur, toute la mémoire, remplir le disque dur, utiliser toute sa pile, etc. J'ai alors cherché comment détecter ces situations de crise. D'ailleurs elles ne doivent pas être vue comme critiques mais normales et il faut les avoir à l'esprit en écrivant un programme. Effectivement, les ressources sont limitées : il faut apprendre à partager.

Limiter la mémoire

Sous Linux, on peut utiliser resource.setrlimit(RLIMIT_AS, ...). Si la mémoire totale dépasse max_mem, une exception MemoryError est émise par Python.

J'ai implémenté une fonction limitedMemory() qui va limiter temporairement la mémoire : lire memory.py d'hachoir_core. L'erreur apparait si la mémoire grossit de la quantité d'octets indiquée. Il suffit alors d'utiliser « try: limitedMemory(maxmem, ...) except MemoryError: ... ».

Limiter le temps processeur

Pour éviter que le programme reste bloqué au même endroit pendant un temps excessif (cas typique : une boucle infinie), il faut pouvoir appeler une fonction avec une durée maximale. Sous Linux, on peut utiliser au choix : time.alarm() ou resource.setrlimit(RLIMIT_CPU, ...). À noter que pour la seconde solution, les pauses (time.sleep()) et le temps passé dans le noyau ne sont pas pris en compte : il vaut donc mieux utiliser une alarme. Une alarme déclanche un signal SIGALRM alors que RLIMIT_CPU va générer un signal SIGXCPU.

J'ai implémenté les deux méthodes dans la fonction limitedTime(sec) : lire timeout.py d'hachoir_core.

Lorsque c'est possible, il vaut mieux utiliser des fonctions offrant déjà cette fonctionnalité comme par exemple la fonction select().

Limiter la pile

En testant dpkg, j'ai réussi à le planter avec « COLUMNS=10000000 dpkg -l ». Après investigation, il s'est avéré que l'erreur venait de la libc (chose qui semblait impensable à mes yeux). En creusant encore, j'ai vu que vfprintf() utilisait massiment la pile pour écrire la sortie de dpkg (qui configure stdout pour ne pas utiliser de tampon).

Bref, j'ai cherché à voir s'il était possible d'attraper l'erreur « épuisement de la pile ». Et bien sûr que oui : c'est possible ! Par contre, quand la pile est hors-service, hors de question d'utiliser printf() ou autre fonction succeptible de réutiliser la pile. Linux permet d'utiliser une pile dédiée aux gestionnaires de signaux. Ah là là, il est quand même fort ce système d'exploitation, hein !

Les fonctions clés sont sigaltstack() pour créer une pile dédiée à notre gestionnaire de signal, sigaction() pour appeler notre fonction quand le signal SIGSEGV est émis, setjmp()/longjmp() pour quitter le code bogué et revenir à la « borne de sauvegarde » (renseignée par setjmp()).

Exemple d'implémentation : stack.c.

En réunissant tous ces élements (try/except, limiter la mémoire, temps et pile), je pense qu'on peut commencer à écrire des programmes robustes. Bien sûr, rien ne vaut un audit minutieux du code source.

dimanche 22 avril 2007

Initiation au fuzzing

Le fuzzing est un outil de test logiciel qui consiste à injecter des données incorrectes pour rechercher des erreurs dans un programme, plus particulièrement dans le but de trouver des failles de sécurité. Aujourd'hui (en 2007), cette méthode est extrêmement efficace ! Disons que globalement, aucun programme ne résiste au fuzzing : ils finissent tous par montrer des faiblesses (qui se manifeste la plupart du temps par un plantage) dans un temps plus ou moins court.

Mon expérience du fuzzing

J'avais lu beaucoup de rapports de fuzzing montrant clairement de grosses faiblesses dans quasiment l'ensemble des logiciels testés. Mais je n'y croyais qu'à moitié, il fallait que je le vois de mes propres yeux. J'ai alors écrit un programme de fuzzing pour mon projet Hachoir. Durant deux semaines j'ai continuellement corrigé des bugs plus ou moins critiques. Comme quoi, la technique fonctionne très bien !

J'ai ensuite adapté mon programme de fuzzing pour tester d'autres applications. J'ai testé sur la suite Image Magick (manipulation de photos)... que je suis arrivé très rapidement à faire planter. J'ai isolé deux cas critiques : pour une image XCF de 80 Ko, Image Magick allouait 1 Go de mémoire (ce qui est énorme), et pour une image TGA, Image Magick consommait toute la puissance du processeur (100% du CPU) durant plusieurs minutes (je n'ai pas eu la patience de mesurer le temps exact). J'ai tenté de rapporter le bug mais je n'ai eu aucun retour.

Je me suis alors senti poussé des ailes et je me suis senti invinsible :-) Tant qu'à faire, allons tester un élément de sécurité ! J'ai choisi au pif l'anti-virus ClamAV... que j'ai réussi assez rapidement à mettre à genoux. Un document Word forgé prend 2 Go de disque dur et l'ensemble du processeur pendant plusieurs minutes. J'ai rapporté le bug qui a été classé comme critique et sera corrigé dans la prochaine version.

Écriture du programme de fuzzing

En pratique, pour Hachoir, Image Magick et ClamAV : je suis parti de fichiers valides (le format dépendant de l'outil testé) que j'ai ensuite tronqué et/ou j'y ai inséré des octets aléatoires. Je passe alors ce fichier forgé au programme testé. Cette algorithme est celui du programme « mangle.c » écrit par le belge Ilja van Sprundel que j'ai réécrit en Python. J'ai ensuite ajouté d'autres opérations comme modifier plusieurs octets à la fois, incrémenter/décrémenter un octet, insérer des valeurs spéciales, etc.

Ce qui me fait peur, c'est que globlament mon programme de test reste extrênement simple et pourtant j'arrive à faire planter très rapidement (moins de 5 minutes) tous les programmes que j'ai testés. Je n'ose même pas imaginer ce qu'on pourrait découvrir avec des programmes beaucoup plus intelligents. Et justement, l'été dernier des conférences ont présenté des logiciels de fuzzing utilisant des algorithmes génétiques ainsi qu'une grammaire dédiée au fuzzing. Le but étant, en gros, d'arriver le plus profondément possible dans le programme cible. Ils utilisent un débogueur dédié ainsi qu'un outil permettant de mesurer la couverture du code (quantité de code exécuté dans le programme cible).

Je pense qu'en couplant un fuzzing avec un outil comme Valgrind, on pourrait créer des outils beaucoup plus intelligents car on connaitrait la couverture du code mais également les erreurs d'accès mémoire.

Le fuzzing étant assez nouveau pour moi, je ne saurai conseiller un site web en particulier. En attendant, suivez les liens donnés sur la page Fuzzing de mon wiki. Je la ferai vivre au fur et à mesure des mes recherches.

vendredi 20 avril 2007

Suivez l'actualité avec RSS

RSS permet de recevoir chez soi, sans se bouger les fesses (ni la souris), gratuitement, les nouveaux articles des sites Internet proposant ce service. Or ça tombe bien, aujourd'hui tous les sites le proposent. Je suis longtemps resté éloigné du buzz RSS car ça ne m'intéressait tout simplement pas. Et puis un jour j'ai remarqué que j'avais un logiciel (Akregator) préinstallé par la suite Kontact. J'ai alors ajouté mon premier flux (linuxfr de mémoire), puis un autre, etc. Aujourd'hui j'en ai une tripoté et j'avoue que je suis devenu fan.

Avantages du RSS :

  • Moindre effort (j'aime !) : se met à jour tout seul, pas besoin d'aller sur 20 sites différents quotidiennement : chaque heure les nouvelles fraiches viennent à vous (et non le contraire)
  • Suivre l'actualité : encore une fois, étant donné que c'est mis à jour tout seul : on peut suivre l'actualité de sites Internet à faible traffic (ex: une nouvelle par mois). Ceci me permet de suivre des blogs rarement mis à jour (ex: le mien).
  • Mise en forme épurée : pas de publicité, pas d'habillage bariollé ou encore une largeur de texte fixe. On reçoit le texte brut, quelques liens et parfois une image.

Désavantages du RSS :

  • Nouvelle drogue : comme pour le courriel, je me suis surpris à appuyer frénétiquement sur le bouton « rafraichir » pour recevoir toujours plus d'articles. À utiliser avec modération. Je me désinscris de temps en temps à des flux inintéressants ou qui me prennent trop de temps.
  • Pas de commentaire : il n'y a que le texte original, pas les commentaires. Il faut aller sur le site internet (un lien direct est donné) pour les obtenir. J'ai vu qu'il existe des flux dédiés aux commentaires mais je crains que ça soit une drogue dure :-/

Trève de blabla, voici ma liste de flux (en vrac). J'indique les thèmes principaux.

Blogs (faible traffic : 1 à 10 articles par mois) :

  • (fr) Biologeek : Python, Django, biologie.
  • (fr) devloop : Sécurité informatique, logiciel libre, Linux.
  • (fr) Thomas Petazonni : Logiciel libre, Debian, programmation.
  • (fr) yeKcim : Ubuntu, jeux libres, littérature, dessin, humour.
  • (fr) Tarek : Python et programmation.
  • (en) Glandium : Programmation, Debian, logiciel libre.
  • (en) Sam Hocevar : Programmation et Debian

Python :

  • (en) Daily Python-URL! : Python, Python, Python et Python (drogue dure ! jusqu'à 40 articles par jour)
  • (en) Python News : Sorties des nouvelles versions de Python (très faible traffic)

Logiciel libre :

  • (fr) Wormux : le jeu Wormux
  • (fr) Dépêches linuxfr.org : Logiciel libre au sens très large, Linux, *BSD (de 1 à 5 articles par jour)
  • (fr) Journaux linuxfr.org : Même thème que les dépêches + du n'importe quoi (drogue dure ! jusqu'à 10 articles par jour)
  • (en) Debian Package of the Day : Un nouveau logiciel Debian par jour (dumoins en théorie : en pratique c'est plutôt 10 par mois voir moins)

Photo du jour de Wikipédia (format 400x300 pixels), ce service vient d'être créé il y a à peine une semaine :

Pour finir, RSS de ce blog : RSS du blog Haypo.

jeudi 12 avril 2007

Mes correctifs Python intégrés dans le trunk officiel

La nuit porte conseil. J'ai continué à traquer les bugs que j'avais trouvé dans Python (rappel : plantage de Python lorsque la mémoire est épuisée) et j'en ai trouvé un autre (comparaison d'un entier court et d'un entier long). Je les ai isolés et corrigés.

J'ai alors écrit un rapport de bug sur Sourceforge et j'ai contacté des développeurs Python sur IRC (salon #python-dev du serveur Freenode). Ils sont très sympas et réactifs.

Finalement, mes correctifs ont été appliqués dans le trunk de Python (la version de développement) et feront partie de Python 2.5.2 (la version 2.5.1 étant en cours de finalisation). 48h pour corriger un bug, je trouve ça tout de même très court comme délai quand on sait que Microsoft Windows et Internet Explorer ont des bugs vieux de plus de 6 ans :-)

mercredi 11 avril 2007

Qui veut gagner de l'argent en Masse

« Qui veut gagner de l'argent en Masse » est une parodie du jeu télévisé « Qui veut gagner des millions » avec Gad Elmaleh et Olivier. Pour avoir été au Québéc, je suis plié de rire en écoutant l'imitation de l'accent québécois. On remarquera le magnifique pull de Guy Saint Hilaire.

Quelques citations remarquables :

  • (1min)
    • M: Vous pouvez gagner jusqu'à un million de dollars. Mais qu'est-ce vous allez faire avec tout cet argent si vous gagnez ?
    • G: Ben disons que si j'arrive à ce niveau du jeu, j'pense que je quitterais ma femme et je me paierai des putes de luxe.
    • M: Mais comme je vous comprend !
  • (3min)
    • M: Guy, ne vous lancez pas à l'emporte pièce. Réfléchissez.
    • G: Marcel, si je m'arrête là, combien j'ai ?
    • M: Vous nous devrez un million de dollars.
  • (4min)
    • M: Mais qui allez-vous appeler ?
    • G: Garou
    • M: Garou ? L'intermittent ?
  • (6 min)
    • « Lorsqu'on invite un pancake à une Barmitzva les convives doivent :
    • (A) l'inciter à boire à l'Open Barmitzva
    • (B) lui présenter Raymond Barmitzva
    • (C) lui offrir des malabarmitzva
    • (D) la réponse D »
  • (9 min)
    • G: Marcel, je vais demander le moit'-moit'
    • M: Computer ? ... (rires) ... vous allez retirer deux mauvaises réponses
    • G: Marcel est-ce que je peux demander exceptionnellement le super moit'-moit' ?
    • M: Computer... procédez au super moit'-moit'

Pour voir ce sketch de 11 minutes, vous avez le choix :

Le sketch doit être ancien mais je ne me lasse pas de le revoir ;-)

mardi 10 avril 2007

Sites internets sur la sécurité informatique

Alors que je tentais, comme tous les mois, de vider ma liste de « [liens] favoris », j'ai réalisé que j'avais accumulé pas mal de liens vers des sites de sécurité informatique. Bien que je ne me suis pas donné le temps de les parcourir en profondeur, ils semblent tous fort intéressants. Voici donc ma petite liste du moment.

Mois des bugs (« Month of xxx bugs ») :

Blogs (liens vers la catégorie sécurité) :

Sites d'actualités :

  • Security Focus : Articles d'actualité
  • frSIRT : Veille sur les dernières alertes de sécurités

À la quête du Programme Parfait

Alors que j'écrivais un fuzzer pour Hachoir, j'ai commencé à trouver de vilains bogues dans Python. Ce récit va vous amener aux frontières des tests logiciels.

L'objectif de mon fuzzer est de trouver un maximum de bogues pour que je puisse ensuite les corriger. Le principe de mon fuzzer est de partir d'un fichier valide, d'y injecter quelques octets aléatoires, puis de tenter d'utiliser ce fichier « verrolé ». Cette technique marche extrêment bien : voyez le fuzzer généraliste de sam pour vous en convaincre.

Lire la suite

mercredi 4 avril 2007

Nouvelles d'hachoir-metadata

hachoir-metadata est un programme permettant de lire les métadonnées d'un fichier : taille d'une image, auteur d'une vidéo, durée d'un son, etc. Il repose sur hachoir-parser pour lire les informations d'un fichier.

Traitements automatiques

hachoir-metadata réalise de plus en plus de traitements automatiques haut niveaux tels que :

  • supprimer les espaces inutiles
  • ignorer les chaînes de caractère vides
  • filtrer les valeurs : ignore les valeurs abbérantes (ex: image ayant une largeur nulle)
  • supprimer les doublons

La suppression des doublons ne concerne pas simplement les valeurs identiques. Pour les chaînes de caractère, hachoir-metadata est capable de reconnaître qu'une chaîne est le début d'une autre. Exemple : si on trouve les deux auteurs "James Brown" et "James Br" pour une chanson, seule la chaîne la plus longue est conservée (James Brown !).

Réutilisation des valeurs

L'extracteur de métadonnée est de plus en plus rigoureux : les valeurs doivent être d'un type précis. Par exemple, la durée d'une chanson est maintenant du type Python « timedelta ». Avant les dates, durées, débit en bit/sec, nombre de canaux audios étaient tantôt une chaîne de caractère, tantôt un entier, tantôt une date, ...

Le fait que le type des données soit strict a permis de faire des calculs sur les documents multimédias. On peut maintenant obtenir le débit en bits par seconde pour du son et de la vidéo, et le taux de compression pour une image et du son. Ceci permet de comparer la qualité d'un codec.

Option --quality

J'ai également ajouté l'option --quality permettant de choisir la « qualité » des métadonnées extraites. En fait, cette option détermine la vitesse d'extraction : les opérations lourdes ne seront faites que pour quality=1.0, alors que pour quality=0.0 toutes les opérations lentes sont ignorées. Cette option influe par exemple sur le calcul de la durée d'un MP3 à débit variable : pour un calcul exact, il faut lire le fichier en entier mais ceci est très long. L'option quality va donc faire varier le nombre de champs traités.

Lire la suite

Nouvelles d'Hachoir (core et parser)

Je viens de me rendre compte que ça fait pas mal de temps que je code sans écrire de journal sur les derniers développement de mon projet Hachoir. Voici donc un premier billet donnant des nouvelles du front.

hachoir-core

hachoir-core est le cœur d'Hachoir : la partie bas niveau qui va découper un fichier en une multitudes de champs. Mais ce composant contient également énormément d'outils divers comme une humanDuration() qui va convertir une durée en une représentation « humaine » (ex: "22 sec 320 ms"). Aujourd'hui, hachoir-core évolue peu car il commence à couvrir l'ensemble des besoins d'un parseur.

Le plus gros changement récent est la tolérance aux erreurs. En fait, l'erreur n'est pas corrigée mais rattrapée. Par exemple, si une erreur est détectée durant la génération de la description d'un champ : l'erreur est affichée et la description devient une chaîne vide. Ceci peut sembler naturel, mais ce n'était pas le cas avant. Précédemment, si la génération d'une description échouait, on perdait beaucoup d'informations car l'erreur déclanchait une cascade d'autres erreurs et finalement plusieurs champs étaient détruits. Ce principe de rattrapage d'erreurs est utilisé dans un maximum de code. Il reste peu de fonctions qui ne sont pas « protégées » ce qui rend le code toujours plus robustes.

hachoir-parser

hachoir-parser est un ensemble de parseurs de fichiers (images, vidéos, archives, programmes, ...). Ce composant est celui auquel contribue le plus de monde car il est simple de le modifier (corriger) ou d'ajouter son propre parseur. J'ai notamment reçu un gros coup de main de Christophe GISQUET qui a écrit les parseurs ACE, RAR, Torrent et d'autres. Mike Melanson, le chef de projet du greffon Flash pour Linux, a également écrit des parseurs pour les formats Real Audio et Real Media. Enfin, Olivier SCHWAB a écrit un parseur 7-zip.

La liste des ajouts récents de parseur montre la forte activité de ce composant :

  • Archive : archive ACE, Microsoft cabinet (CAB), Roshal archive (RAR), archive Microsoft (MAR)
  • Audio : Uncompressed amiga module (MOD), ScreamTracker3 module (S3M), FastTracker II Extended Module (XM), Audio Interchange File Format (AIFF et AIFC), Real audio (RA), image Targa (TGA)
  • Image : Photoshop (PSD), icone animé Windows (ANI), Aldus Placeable Metafile (APM), Microsoft Enhanced Metafile (EMF) et Microsoft Windows Metafile (WMF)
  • Divers : BitTorrent (.torrent), police de caractère TrueType (TTF), document PDF, exécutable Windows 16-bit (NE), vidéo MPEG-2 Transport Stream (MPEG TS), raccourci Windows (LNK), X11 Portable Compiled Font (PCF), aide Windows HTML (CHM), ...

À l'heure actuelle il y a 70 parseurs dans la version de développement d'Hachoir. J'ai du mal à savoir si c'est beaucoup ou peu. En consultant la liste complète des parseurs, je pense tout de même que c'est assez conséquent pour ne pas dire énorme. Il faut d'ailleurs savoir que certains parseurs gèrent plusieurs formats. Exemples : RIFF parse les formats AVI, WAV, ANI et CDA; WMF parse les formats AMF, EMF et WMF; etc.