Euh, autant je suis d'accord sur la quantité de code à auditer, autant je ne le suis absolument pas sur la seconde phrase. Le risque d'une faille dans le noyau se situe à deux niveaux : d'une, sous Unix, ce qui est dans le noyau est tout ce qui est "commun à toutes les applications", et donc ce qui est globalement vital au système ; de deux, tout ce qui est dans le noyau tourne avec les privilèges spéciaux sur le matériel. Pour le premier, on est d'accord, ça ne change rien. Si il y a un DoS potentiel sur, disons, la couche de gestion de la mémoire physique, on entraîne tout le système. Pour le second, en revanche, ça change tout. Je peux certes entraîner le système, éventuellement gagner des droits root, mais je ne peux pas me hisser dans le kernel space comme ça se voit assez régulièrement.
De façon plus générale : en séparant les parties qui peuvent l'être, en définissant clairement quelles sont leurs relations et séparations, on permet plusieurs choses :
Tout ce qui n'est pas purement vital au système, s'il se retrouve attaqué, n'entraîne que lui. La pile TCP/IP n'est pas vitale au système. Le driver son l'est encore moins. Chacun étant des applications tournant dans leur propre espace d'adressage, utilisant leur propre mémoire, elles n'entraîneront qu'elles-mêmes dans leur chute. On l'a vu, d'ores et déjà, il y a quelques années, quand un serveur Web sous GNU/Hurd avait subi un /.age en règle : la pile TCP/IP s'était vautrée un nombre incalculable de fois, la machine pas.
On peut réellement réfléchir aux permissions nécessaires à telle ou telle application. Sous Unix, la tradition veut que la plupart des parties considérées comme "centrales" se retrouvent intégrées dans le noyau. Souvent par besoin, du fait de sa conception. Parfois par commodité. Certaines parties se trouvent avoir besoin de permissions spéciales, et en effet certains serveurs sont très privilégiés sous GNU/Hurd (ils tournent en root, et L4 ne leur restreint aucun appel système). Ces serveurs sont sensibles, et facilement identifiables comme tels. Mais un grand nombre d'autres (et je pense aux pilotes de périphérique, par exemple) ne nécessitent "que" de tourner en root (et encore, pas tous !). Ces parties deviennent de suite moins critiques. Il y a donc un double gain : un gain de clarté pour l'identification des parties centrales, sensibles ; un gain de sécurité lié aux privilèges donnés concrètement aux applications.
C'est une évidence, mais il est bien plus facile d'auditer un code entièrement organisé en composants indépendants qu'un code "monolithique". Les effets de bord sont bien moins complexes, d'une part. On a souvent vu des horreurs comme des off by one dans un bout de code aboutir à une erreur de calcul assez embêtante de la taille d'un tableau, qui avec l'arrondi nécessaire se retrouvait assez pour être exploitable, ou potentiellement exploitable. Inutile de dire qu'une telle erreur est quasiment indétectable, et qu'un audit qui irait jusqu'à les rechercher prendrait des années. D'autre part, la séparation claire et revendiquée amène à faire quelque chose que Linus Torvalds s'est toujours refusé à faire pour Linux : concevoir des interfaces, stables tant que possible. La série de failles locales récentes découvertes dans Linux étaient liées à des comportements erratiques lorsque telle option était à telle valeur, tel pointeur à telle autre, etc., etc. Avoir des interfaces en mouvement constant, tandis que le code les utilisant l'est pas forcément du tout, n'aide pas à prévenir ce genre de problèmes. Je sais d'expérience que je me rends compte du comportement lors des cas limites principalement lorsque je documente mes fonctions/interfaces attentivement. Chose qu'évidemment, je ne ferai pas si elles sont destinées à être modifiées dans deux mois. Et chose qui n'est pas faite avec Linux. Les interfaces du Hurd, elles, sont stables. Il n'y a eu globalement qu'un changement qui a tout cassé (cassé l'ABI) depuis la première stabilisation. Bien entendu, on ne peut pas exclure qu'il y en ait d'autres, mais elles seront très, très limitées. Plus de clarté, à mon sens, c'est plus de sécurité, et c'est aussi une meilleure utilisation de ces interfaces, donc moins prône aux erreurs.
Pour exemple, le coeur du système d'authentification du Hurd, représente 358 lignes de code (comptées par sloccount ;-). C'est LA partie du système qui nécessite de tourner en root, et qui nécessite d'être complètement et entièrement de confiance. 358 lignes, je pense que c'est faisable de l'auditer. Bon courage pour faire la même chose sur un Unix ;-)
[^] # Re: sécurité des serveurs
Posté par Manuel Menal . En réponse à la dépêche Hurd : nouvelle version de Debian GNU/Hurd et avancée du port sur L4. Évalué à 10.
De façon plus générale : en séparant les parties qui peuvent l'être, en définissant clairement quelles sont leurs relations et séparations, on permet plusieurs choses :
Tout ce qui n'est pas purement vital au système, s'il se retrouve attaqué, n'entraîne que lui. La pile TCP/IP n'est pas vitale au système. Le driver son l'est encore moins. Chacun étant des applications tournant dans leur propre espace d'adressage, utilisant leur propre mémoire, elles n'entraîneront qu'elles-mêmes dans leur chute. On l'a vu, d'ores et déjà, il y a quelques années, quand un serveur Web sous GNU/Hurd avait subi un /.age en règle : la pile TCP/IP s'était vautrée un nombre incalculable de fois, la machine pas.
On peut réellement réfléchir aux permissions nécessaires à telle ou telle application. Sous Unix, la tradition veut que la plupart des parties considérées comme "centrales" se retrouvent intégrées dans le noyau. Souvent par besoin, du fait de sa conception. Parfois par commodité. Certaines parties se trouvent avoir besoin de permissions spéciales, et en effet certains serveurs sont très privilégiés sous GNU/Hurd (ils tournent en root, et L4 ne leur restreint aucun appel système). Ces serveurs sont sensibles, et facilement identifiables comme tels. Mais un grand nombre d'autres (et je pense aux pilotes de périphérique, par exemple) ne nécessitent "que" de tourner en root (et encore, pas tous !). Ces parties deviennent de suite moins critiques. Il y a donc un double gain : un gain de clarté pour l'identification des parties centrales, sensibles ; un gain de sécurité lié aux privilèges donnés concrètement aux applications.
C'est une évidence, mais il est bien plus facile d'auditer un code entièrement organisé en composants indépendants qu'un code "monolithique". Les effets de bord sont bien moins complexes, d'une part. On a souvent vu des horreurs comme des off by one dans un bout de code aboutir à une erreur de calcul assez embêtante de la taille d'un tableau, qui avec l'arrondi nécessaire se retrouvait assez pour être exploitable, ou potentiellement exploitable. Inutile de dire qu'une telle erreur est quasiment indétectable, et qu'un audit qui irait jusqu'à les rechercher prendrait des années. D'autre part, la séparation claire et revendiquée amène à faire quelque chose que Linus Torvalds s'est toujours refusé à faire pour Linux : concevoir des interfaces, stables tant que possible. La série de failles locales récentes découvertes dans Linux étaient liées à des comportements erratiques lorsque telle option était à telle valeur, tel pointeur à telle autre, etc., etc. Avoir des interfaces en mouvement constant, tandis que le code les utilisant l'est pas forcément du tout, n'aide pas à prévenir ce genre de problèmes. Je sais d'expérience que je me rends compte du comportement lors des cas limites principalement lorsque je documente mes fonctions/interfaces attentivement. Chose qu'évidemment, je ne ferai pas si elles sont destinées à être modifiées dans deux mois. Et chose qui n'est pas faite avec Linux. Les interfaces du Hurd, elles, sont stables. Il n'y a eu globalement qu'un changement qui a tout cassé (cassé l'ABI) depuis la première stabilisation. Bien entendu, on ne peut pas exclure qu'il y en ait d'autres, mais elles seront très, très limitées. Plus de clarté, à mon sens, c'est plus de sécurité, et c'est aussi une meilleure utilisation de ces interfaces, donc moins prône aux erreurs.
Pour exemple, le coeur du système d'authentification du Hurd, représente 358 lignes de code (comptées par sloccount ;-). C'est LA partie du système qui nécessite de tourner en root, et qui nécessite d'être complètement et entièrement de confiance. 358 lignes, je pense que c'est faisable de l'auditer. Bon courage pour faire la même chose sur un Unix ;-)