Journal 306 bugs dans FreeBSD

Posté par  (site web personnel) .
Étiquettes : aucune
0
20
juil.
2005
Un article pas mal sur le logiciel de détection automatique de bugs de Coverity ( http://www.securityfocus.com/print/news/11230(...) ).
J'avais fait une news à l'époque de la détection des plus de 900 bugs du kernel Linux ( http://linuxfr.org/2004/12/17/17904.html(...) ) et voila que maintenant Coverity vient de scruter FreeBSD et de trouver 306 bugs potentiels.
J'ai fait mes petits calculs et si on compare les deux OS on obtient :
Linux 2.6.9 => 5.7 millions de lignes et 985 bugs = 0.17 bugs par milliers de lignes.
FreeBSD => 1.224 millions de lignes et 306 bugs = 0.25 bugs par milliers de lignes...soit 50 % de plus que Linux !

PS : le chiffre de 1.224 millions de lignes pour FreeBSD est obtenu en calculant à partir de l'information de l'article qui indique un bug trouvé pour 4000 lignes (donc 306x4000=1224000).

PS2 : merci de garder un peu d'esprit critique sur tout cet effet d'annonce (Coverity est une société qui veut vendre son produit), sur la nature des bugs (dans le kernel ou juste dans les drivers) et leur danger (accessible par un user ou non).
  • # ?

    Posté par  (site web personnel) . Évalué à 6.

    Et sur le fait, qu'il s'agisse de bugs ou non. Il est fort pour faire des faux positifs leur logiciel...

    Si tu veux le bon nombres de ligne de code utilise sloccount.

    "La première sécurité est la liberté"

    • [^] # Re: ?

      Posté par  (site web personnel) . Évalué à 1.

      >> Si tu veux le bon nombres de ligne de code utilise sloccount.

      Humm...oui mais il me faudrait aussi télécharger les sources de FreeBSD donc ma petite multiplication me suffira amplement.
  • # stats

    Posté par  (site web personnel) . Évalué à 2.

    pour infos, en statistique, ca a a peu de sens de faire des pourcentages sur des ratios surtout sur des chiffres aussi petits.
    on dira plutot qu'il y a 0,08 points de différence entre les deux ratios.
    • [^] # Re: stats

      Posté par  (site web personnel) . Évalué à 3.

      D'un autre côté, est-ce que le code "incriminé" ou "incriminable" est forcément différent entre Linux et BSD? N'y a-t'il pas partage de certains concepts/bouts de code entre les deux noyaux qui fait qu'une erreur de conception dans l'un soit reproduite dans l'autre?
      • [^] # Re: stats

        Posté par  . Évalué à 3.

        s'il y a partage, c'est forcément de FreeBSD vers Linux (question de license, toussa), sauf éventuellement pour une partie du code de ext2 qui est couvert par la GPL.
        • [^] # Re: stats

          Posté par  (site web personnel) . Évalué à 2.

          Comme je ne suis pas expert en licences (je ne connais que les grosses différences entre BSD et Linux), et que d'un autre côté les deux codes sources sont "ouverts" (librement consultables), sans envisager forcément un copier-coller du code source, est-il possible que quelqu'un voulant implémenter le code d'un pilote par exemple dans FreeBSD, s'inspire vraiment très fortement du code Linux, au point de reproduire certaines possibles "erreurs" de conception dans le genre de la non vérification de la longueur de chaînes, de validité de pointeurs, & co.?
          • [^] # Re: stats

            Posté par  . Évalué à 2.

            Oui, surtout s'il copie un pilote Linux sous licence GPL/BSD (il y en a un nombre non négligeable).

            Sinon, c'est franchement improbable, ou alors, ce codeur se livre à du piratage.
            • [^] # Re: stats

              Posté par  . Évalué à 3.

              Pitié :(

              Ce n'est pas du pirtage, mais de la contrefaçon...
        • [^] # Re: stats

          Posté par  . Évalué à 2.

          Pas forcement il y a quelque morceaux dans le kernel sous dual GPL...
        • [^] # Re: stats

          Posté par  . Évalué à 2.

          Et la compabilité binaire ELF ?
          • [^] # Re: stats

            Posté par  . Évalué à 3.

            si tu parles de l'émulation des binaires linux sous freebsd, il semble qu'elle soit sous license BSD (cf /usr/src/compat/linux), sinon, pour une liste des fichiers du noyau couvert par la GPL, un petit grep doit suffire (cf http://x0ra.free.fr/GPLed_file(...) )
            • [^] # Re: stats

              Posté par  (site web personnel) . Évalué à 1.

              Oui mais aucun d'entre eux n'est disponible directement dans le noyau. Ils ne peuvent être compilé directement que en tant que modules. C'est le cas pour le nouveau driver reiserfs
              • [^] # Re: stats

                Posté par  . Évalué à 1.

                effectivement, je viens de regarder un peu plus en détails, quand même pas mal de ces sources sont sous double license:

                * Alternatively, this software may be distributed under the terms of the
                * GNU General Public License ("GPL") version 2 as published by the Free
                * Software Foundation.


                C'est le cas pour le nouveau driver reiserfs
                ça doit être aussi le cas de l'implémentation de XFS qui utilise les sources sous GPL de SGI.
    • [^] # Re: stats

      Posté par  (site web personnel) . Évalué à 1.

      > pour infos, en statistique, ca a a peu de sens de faire des pourcentages sur des ratio

      Dans le cas qui nous est présenté, justement, je trouve ça bien plus pertinent de faire un pourcentage. 0,08 point si c'était entre 50 et 50,08, ça serait une différence mineur, alors qu'entre 0,00017 et 0,00025, je trouve ça assez gros.
      • [^] # Re: stats

        Posté par  (site web personnel) . Évalué à 6.

        pas tellement que ca si tu y penses vraiment
        si on prend les données brutes, sans réfléchir sur les modes de calcul, ca fait 'uniquement' 100 bugs de différence, et c'est peu vis à vis de l'ensemble référrent (le nombre de lignes). les 50% c'est du spectacle.

        n'oublie pas que plus c'est faible, plus ca peut monter rapidement.

        si tu n'es pas convaincu, je te prie de me croire que c'est quelque chose qui ne se fait pas trop en statistiques (en tout cas par les gens sérieux)
        • [^] # Re: stats

          Posté par  (site web personnel) . Évalué à 8.

          Il y a beaucoup de situations en effet ou les gens confondent les points et les utilisent l'un à la place de l'autre.

          Mais je t'assure que pour comparer deux proportions, dire "il y a deux fois plus de graisse dans du fromage 40% de matière grasse que dans du 20%", même des gens sérieux s'y autorisent. Comparer des concentrations en faisant des pourcentages, c'est on ne peut plus clair. Si la quantité de tel ou tel gaz toxique dans l'atmosphère est passé de 1ppm a 2ppm d'une année sur l'autre, tu dira que ça a doublé ou que ça a augmenté de 1ppm ?

          Dire que pour 100 lignes de code de FreeBSD, coverity trouve 50% plus de bugs que dans 100 lignes de code Linux en moyenne, ça a un sens très clair, et c'est exactement ce que dit le journal.
          • [^] # Re: stats

            Posté par  (site web personnel) . Évalué à 0.

            bah ce n'est pas une histoire de confondre quelque chose à la place d'une autre, ca se comprend, je n'en doute pas.
            je dis juste que statistiquement ca n'a pas énormément de sens (volatile etc.).

            bref si tu veux l'utiliser, tu le peux c'est ton droit, à toi de voir si tu as envie d'être précis dans ce domaine.

            PS:
            les comparaisons de matière grasse c'est de l'arnaque.
            http://www.tasante.com/sous_rubrique/bien_etre/alimentation/Pages/p(...)
            En ce qui concerne les fromages, le taux de matière grasse étant calculés sur la matière sèche, plus ils sont humides et moins il sont gras. Par exemple un fromage blanc à 40% de matière grasse est moins calorique qu’un camembert à 25%
    • [^] # Re: stats

      Posté par  (site web personnel) . Évalué à 6.

      Il ne s'agit pas de statistiques !
      Dire que Coverity trouve 50 % plus de bugs par lignes de code dans FreeBSD que dans Linux, c'est juste de l'explication de texte (enfin de nombres plutôt :-) )
  • # Un milliard?!

    Posté par  . Évalué à 7.

    1,224 millions de lignes, et non 1.224 millions, bien sûr...

    Petite remarque : Si tu savais déjà que FreeBSD comportait un bogue (potentiel) pour 4000 lignes, il n'était pas nécessaire de calculer son nombre total de lignes pour en déduire son taux de 0.25 bogues par milliers de lignes.

    De plus, nombre de ces soi-disant bogues sont en réalité sans danger. Ainsi, certains dépassements de tableaux dans des cas où l'on est sûr de disposer de la place nécessaire en mémoire.

    Autre exemple : dans certains cas, le programmeur a placé des sécurités pour traiter des configurations improbables, mais qu'il ne juge pas impossibles. De son côté, le coverity check détecte que la condition testée ne peut jamais être vraie, et le signale donc comme un bogue. Evidemment, c'est plus qu'inoffensif...

    Du coup, ces chiffres peuvent aussi être interprétés comme traduisant une plus grande prudence de la part des programmeurs de FreeBSD.

    J'estime donc qu'en tirer une comparaison entre les qualités des deux noyaux est très, très prématuré.
    • [^] # Re: Un milliard?!

      Posté par  (site web personnel) . Évalué à 2.

      >> Petite remarque : Si tu savais déjà que FreeBSD comportait un bogue (potentiel) pour 4000 lignes, il n'était pas nécessaire de calculer son nombre total de lignes pour en déduire son taux de 0.25 bogues par milliers de lignes.

      pas faux....mais je m'en sort hypocritement en répondant que je voulais une comparaison terme à terme avec le linux 2.6.9 de la news précédente et que donc j'avais besoin du nombre total de lignes.

      >> Ainsi, certains dépassements de tableaux dans des cas où l'on est sûr de disposer de la place nécessaire en mémoire.

      Je croyais que les BSD se permettaient de baver sur Linux en disant que eux ils codaient proprement et correctement ?
      • [^] # Re: Un milliard?!

        Posté par  . Évalué à -1.

        Je croyais que les BSD se permettaient de baver sur Linux en disant que eux ils codaient proprement et correctement ?

        Ah, je ne sais pas, je ne suis pas tellement leur activité... En fait, tout ce que je sais, à ce sujet, c'est qu'on m'a dit que le code d'openssh était assez horrible, et que c'était pour ça qu'on n'en faisait pas une bibliothèque.

        Cela dit, pour en revenir sur la propreté du code, celui qui suit me semble parfaitement propre, malgré son dépassement :

        int i[2];

        [...]

        /* This is an out-by-one, but it's volunteer, and we are sure there is enough place into memory for it. */
        i[2]=0;
        • [^] # Re: Un milliard?!

          Posté par  (site web personnel, Mastodon) . Évalué à 9.

          ??? propre ??? o_O

          Mais c'est absolument dégueulasse ! Et surtout, comment peux-tu être sûr de ton coup ?

          Mes livres CC By-SA : https://ploum.net/livres.html

        • [^] # Re: Un milliard?!

          Posté par  (site web personnel) . Évalué à 4.

          Le problèlme n'est pas forcément un problème de place mémoire, mais plutot un problème d'écrasement de code.

          Je suis sur qu'il doit bien rester un octet en mémoire. Mais suis-je sur que derrière ce tableau, il n'y a pas le code d'un programme qui une fois écraser te feras un bon "Segmentation fault".

          En écrivant des programmes en C, j'ai déjà vu des cas ou des dépassement ne faisait pas planté le programme, au moment du dépassement, mais le faisait planté (ou même marché, mais bizarrement, variable modifié, saut dans le code, ....) que beaucoup plus tard.... Et aprés tu passes des heures car tu ne cherches pas au bonne endroit.
          • [^] # Re: Un milliard?!

            Posté par  . Évalué à 1.

            "Je suis sur qu'il doit bien rester un octet en mémoire."
            On ne peut jamais en être sûr et certain ... je pense plutôt que dans l'exemple, le codeur "sait" que le systeme lui alouera plus que ces 8 octets (sizeof(int) * 2) pour des raisons d'alignement mémoire (32, 64 ...) et qu'à priori, ils resteront "réservés" ...

            Ceci dit, je te rejoints complètement sur ton experience de buffer overflow ... je dirais même que le comportement que tu décris et le plus souvent produit.
            En effet, un programme peut modifier ses octets partout où il le souhaite sans générer un seul SIGSEGV tant qu'il reste dans sa plage de mémoire réservée par le système ; par contre, par la suite, le programme a en effet de forte chances de planter à un moment ou à un autre parce que ces octets modifiés vont modifier aléatoirement son comportement ... Et on aura notre SIGSEGV parce qu'aléatoirement, on a plus de chance de taper hors sa zone mémoire que dedant :-)

            Tiens, ca me rappelle des "challenges informatiques" ... Par exemple, sur un noyau minimum permettant un accés illimité à l'ensemble de la mémoire pour les processus, le but étant de créer un processus capable de corrompre les autres processus tout en assurant sa protection.
            Tous les processus sont déclenchés ex-equo et le survivant faisait gagner son codeur.
            • [^] # Re: Un milliard?!

              Posté par  (site web personnel) . Évalué à 1.

              >En effet, un programme peut modifier ses octets partout où il le souhaite sans générer un seul SIGSEGV tant qu'il reste dans sa plage de mémoire réservée par le système

              Petite imprécision.

              Le programme peut modifier les octets partout où il le souhaite dans ses segments mémoire marqués en écriture (bss/heap/stack etc...) sans générer un seul SIGSEGV.
            • [^] # Re: Un milliard?!

              Posté par  . Évalué à 3.

              Tiens, ca me rappelle des "challenges informatiques" ... Par exemple, sur un noyau minimum permettant un accés illimité à l'ensemble de la mémoire pour les processus, le but étant de créer un processus capable de corrompre les autres processus tout en assurant sa protection.
              Tous les processus sont déclenchés ex-equo et le survivant faisait gagner son codeur.


              Marchera jamais...

              <Ce que j'aurais joué>
              memset du noyau à la valeur de l'instruction "cli", puis mise d'un joyeux "leave iret" à la fin, et victoire assurée (plus d'interruptions horloge, donc plus de main aux autres processus), à moins de jouer en multiproc.
              </Ce que j'aurai joué>

              A mon avis, ça devait être des threads ayant un accès illimité à la mémoire utilisateur, mais pas à celle du noyau. Dommage, mais bon...
        • [^] # Re: Un milliard?!

          Posté par  . Évalué à 3.

          Ah, je ne sais pas, je ne suis pas tellement leur activité

          Ca ce sent

          ... En fait, tout ce que je sais, à ce sujet, c'est qu'on m'a dit que le code d'openssh était assez horrible

          Le mec qui t'a dit ca doit pas suivre tellement leur activité non plus.

          et que c'était pour ça qu'on n'en faisait pas une bibliothèque.

          On dirait que tu suis pas tellement la sécurisation des clients non plus.


          Cela dit, pour en revenir sur la propreté du code, celui qui suit me semble parfaitement propre, malgré son dépassement :

          int i[2];

          [...]

          /* This is an out-by-one, but it's volunteer, and we are sure there is enough place into memory for it. */
          i[2]=0;


          On en pleurerait

          Je préfère quand même


          void* i = calloc(2*sizeof(ulong));
          int* j= (int*) i;
          [...]

          j[1] = (int) NULL;


          Parceque ca compilera jamais deux fois de la même façon sur deux archis différentes. Même les warnings GCC changent à chaque compilation.... Ce qui est encore plsu drôle c'est la liste d'insultes que sort valgrind.

          Bien sur c'est un bonheur pour tous les eptits malins en mal d'attaque par buffer overflow.

          Et ca devient encore plus drole quand on passe j[1] en paramêtre d'une fonction.
        • [^] # Re: Un milliard?!

          Posté par  (site web personnel) . Évalué à 3.

          Fichtre ! En admettant que tu te sois cogné la vérification de la politique de génération de code de ton compilateur, exit la portabilité avec ce genre de considérations.

          Pourtant, c'est simple, sémantiquement "int i[2]" ça veut dire allouer 2 int, ça ne dit rien sur ce qu'il y a autour.

          Pour les autres situations, ça sera un "int *i;", puis "i[0]" ... "i[2]". Dans ce cas, la définition de "i" indique sans aucune ambiguïté que toi, programmeur, tu t'assures d'accéder là où tu peux le faire.


          M'enfin... ce n'est pas parce que le langage C laisse la porte ouverte au code gruick que ça doit devenir la règle.
          • [^] # Re: Un milliard?!

            Posté par  . Évalué à 2.

            Ouah!

            Quatre réponses en une après-midi, chapeau! Bon, je vais vous répondre tous ici, plutôt que de poster quatre réponses.

            En fait, le code que j'ai posté n'était là pour faciliter la compréhension du problème, pas pour fournir un exemple concret. Si vous en voulez un, voilà :

            http://www.uwsg.iu.edu/hypermail/linux/kernel/0503.3/0957.html(...)

            L'exemple que j'ai posté n'en était qu'une version simplifiée. Donc, comme vous le voyez, on peut faire des off-by-one (et pas out-by-one, comme je l'avais écrit précédemment, mea culpa) raisonnablement propres, au point de les intégrer le noyau Linux en toute connaissance de cause.

            Pour ma part, j'ai déjà procédé à l'inverse : de magnifiques packet[-1] parsemaient mon code, et je t'assure que c'était parfaitement correct (c'était pour accéder à l'en-tête d'un paquet, dans une pile réseau), et proprement documenté (par l'intermédiaire des commentaires, encore une fois).

            Donc, sisisisi, ce style de codage est parfaitement acceptable, il ne casse pas nécessairement la portabilité, ce qui compte, c'est qu'il soit effectué avec précaution, et bien explicité.

            En revanche, je veux bien croire que ce genre de choses ne soit jouable qu'en espace noyau, où les informations dont le programmeur dispose sont nettement plus importantes qu'en espace utilisateur (il connait, ou peut connaître, la position physique de son code, le déplacer si nécessaire, kmalloc() alloue toujours des zones mémoires de tailles 2^n, d'où d'autres informations, etc...).

            Et pour conclure, les expériences vécues sur des off-by-one involontaires en espace utilisateur ne sont absolument pas transposables à des off-by-one volontaires en espace noyau.

            On peut donc parfaitement effectuer des off-by-ones sans commettre de bogue.
            • [^] # Re: Un milliard?!

              Posté par  (site web personnel) . Évalué à 1.

              la norme C est claire là-dessus : tu peux faire un peu ce que tu veux comme arithmétique de pointeurs (addition, sousraction) tant que les opérandes et le résultats pointent sur un élément de bloc (array object) existant ou l'élément juste suivant« one past the last element of the array object »)

              Dans ton exemple, ça veut dire que l'on peut considérer i, i+1, et aussi i+2. Par contre la norme dit bien qu'on a pas le droit de déréférencer le i+2 « If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated. »
              Donc, nan, ton i[2] = 0; ne va pas.

              Pariel, pour les truc[-1], tout dépend comment tu as obtenu truc. Si c'est comme ça, pas de problèmes :

              int *machin = malloc (42 * sizeof (int));
              int *truc = machin + 1;
              • [^] # Re: Un milliard?!

                Posté par  . Évalué à 2.

                Donc, nan, ton i[2] = 0; ne va pas.

                Alors, c'est une extension à la norme, parce que, de fait, ça marche. Evidemment, il faut savoir ce qu'on écrase éventuellement, mais ça marche, je viens de le vérifier manuellement en espace utilisateur.

                Pariel, pour les truc[-1], tout dépend comment tu as obtenu truc. Si c'est comme ça, pas de problèmes :

                [...]


                C'était approximativement ça :-) .
                • [^] # Re: Un milliard?!

                  Posté par  (site web personnel) . Évalué à 3.

                  c'est un UB : le fait que ton test ait marché une fois ne garanti pas que ça marchera toujours.

                  Il est tout à fait possible que ton tableau i soit dans une page où tu as le droit d'écrire et que, pas de bol, i+2 pointe pile sur le début d'une page où tu n'as pas le droit d'écrire. Et là i[2] = 0 ⇒ SIGSEGV.

                  On pourrait écrire je pense un programme C qui fait ça (avec un peu de mmap()) mais j'ai la flemme :)
            • [^] # Re: Un milliard?!

              Posté par  (site web personnel) . Évalué à 3.

              Ton exemple de code linux est extrèment particulier, en gros on voit trainer un int[108] et il écrit en tab[108] car parce qu'il sait parfaitement que le buffer kernel sont en 2^n, donc si tab[107] est valide tab [108] l'est forcément aussi.

              Quand tu écris tab[i], le compilo C ne peut pas savoir à tous les coups la taille de tab, pour cela il doit faire une étude global de pointeurs qui n'ira pas forcément loin (paramètre de fonction en int tab[], etc...).

              Donc en écrivant tab[i], le compilo comprend prend la base pointé par tab et donne moi le ième élément. Il n'y a aucune notion de taille, et ne te dira jamais rien.

              donc tab[i] <=> *(tab+i) (modulo des optimisations possibles)
              <=> * (typeof(tab)) ((int)tab + i * sizeof(*tab))

              Le segfault ne peut venir que par acces à une mauvaise page mémoire. Les pages système x86, font 4ko. donc si tu alloues 100 octets, tu "un certain nombre" d'octet accessible derrière sans planter. La gestion du malloc empile les bloc mémoires ainsi allouer à la queuelele.

              Donc, si tu fais un off by one, tu peux sois écrasé d'autres donnés (super top à debugguer et vive lib efence ou valgrind), soit tomber sur une page interdite et planter.

              Le cas du kernel est encore plus violent : il utilise une grosse page de 4Mo : il n'y a _pas_ de protection mémoire dans le kernel.

              "La première sécurité est la liberté"

      • [^] # Re: Un milliard?!

        Posté par  (site web personnel) . Évalué à 3.

        Je croyais que les BSD se permettaient de baver sur Linux en disant que eux ils codaient proprement et correctement ?

        Je ne suis pas sûr qu'on puisse jeter l'opprobe sur l'ensemble des noyaux BSD sur ce point : c'est surtout Theo de Raadt qui parle souvent au sujet d'OpenBSD qui met en avant ce point.
        NetBSD un peu aussi, mais moins "fortement", eux mettent l'accent sur la propreté du code pas forcément dans un but de sécurité, mais plutôt de portabilité.
        Pour FreeBSD, je ne connais pas assez.
  • # coverity sur coverity ?

    Posté par  . Évalué à 10.

    Et juste pour savoir, se logiciel a détecté combien de bugs potentiels dans son propre code ?

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.