web-dev-qa-db-fra.com

Pourquoi strlcpy et strlcat sont-ils considérés comme non sécurisés?

Je comprends que strlcpy et strlcat ont été conçus comme des remplacements sécurisés pour strncpy et strncat. Cependant, certaines personnes sont toujours d'avis qu'elles sont peu sûres et provoquent simplement un type de problème différent .

Quelqu'un peut-il donner un exemple de l'utilisation de strlcpy ou strlcat (c'est-à-dire une fonction qui toujours null termine ses chaînes) peut entraîner des problèmes de sécurité?

Ulrich Drepper et James Antill affirment que cela est vrai, mais ne fournissent jamais d'exemples ni ne clarifient ce point.

75
Anonymous

Premièrement, strlcpy n'a jamais été conçu comme une version sécurisée de strncpy (et strncpy n'a jamais été conçu comme une version sécurisée de strcpy). Ces deux fonctions sont totalement indépendantes. strncpy est une fonction qui n'a aucune relation avec les chaînes C (c'est-à-dire les chaînes terminées par null). Le fait qu'il ait le str... le préfixe de son nom n'est qu'une erreur historique. L'histoire et le but de strncpy sont bien connus et bien documentés. Il s'agit d'une fonction créée pour travailler avec des chaînes dites de "largeur fixe" (pas avec des chaînes C) utilisées dans certaines versions historiques du système de fichiers Unix. Certains programmeurs sont aujourd'hui confus par son nom et supposent que strncpy est en quelque sorte censé servir de fonction de copie de chaîne C de longueur limitée (un frère "sécurisé" de strcpy), qui en réalité est un non-sens complet et conduit à de mauvaises pratiques de programmation. La bibliothèque standard C dans sa forme actuelle n'a aucune fonction pour la copie de chaîne C de longueur limitée. C'est là que strlcpy entre en jeu. strlcpy est en effet une véritable fonction de copie de longueur limitée créée pour travailler avec des chaînes C. strlcpy fait correctement tout ce qu'une fonction de copie de longueur limitée doit faire. La seule critique que l'on puisse viser est qu'il n'est malheureusement pas standard.

Deuxièmement, strncat d'autre part, est en effet une fonction qui fonctionne avec les chaînes C et effectue une concaténation de longueur limitée (il s'agit en effet d'un frère "sécurisé" de strcat). Pour utiliser correctement cette fonction, le programmeur doit faire particulièrement attention, car le paramètre de taille accepté par cette fonction n'est pas vraiment la taille du tampon qui reçoit le résultat, mais plutôt la taille de sa partie restante (également, le caractère de terminaison est compté implicitement). Cela peut être déroutant, car pour lier cette taille à la taille du tampon, le programmeur doit se rappeler d'effectuer des calculs supplémentaires, ce qui est souvent utilisé pour critiquer le strncat. strlcat s'occupe de ces problèmes, en changeant l'interface afin qu'aucun calcul supplémentaire ne soit nécessaire (au moins dans le code appelant). Encore une fois, la seule base sur laquelle je puisse critiquer est que la fonction n'est pas standard. En outre, les fonctions du groupe strcat sont quelque chose que vous ne verrez pas très souvent dans le code professionnel en raison de la facilité d'utilisation de l'idée même de concaténation de chaînes basée sur une nouvelle analyse.

Quant à savoir comment ces fonctions peuvent entraîner des problèmes de sécurité ... Elles ne le peuvent tout simplement pas. Ils ne peuvent pas conduire à des problèmes de sécurité dans une plus grande mesure que le langage C lui-même peut "conduire à des problèmes de sécurité". Vous voyez, pendant un certain temps, il y avait un fort sentiment que le langage C++ devait évoluer dans le sens de se développer en une étrange saveur de Java. Ce sentiment se répand parfois également dans le domaine du langage C, ce qui entraîne une critique plutôt désemparée et forcée des fonctionnalités du langage C et des fonctionnalités de la bibliothèque standard C. Je soupçonne que nous pourrions aussi avoir affaire à quelque chose comme ça dans ce cas, bien que j'espère sûrement que les choses ne sont pas vraiment si mauvaises.

105
AnT

La critique d'Ulrich est basée sur l'idée qu'une troncature de chaîne qui n'est pas détectée par le programme peut entraîner des problèmes de sécurité, à travers une logique incorrecte. Par conséquent, pour être sûr, vous devez vérifier la troncature. Faire cela pour une concaténation de chaînes signifie que vous effectuez une vérification dans le sens de ceci:

if (destlen + sourcelen > dest_maxlen)
{
    /* Bug out */
}

Maintenant, strlcat effectue effectivement cette vérification, si le programmeur se souvient de vérifier le résultat - donc vous pouvez l'utiliser en toute sécurité:

if (strlcat(dest, source, dest_bufferlen) >= dest_bufferlen)
{
    /* Bug out */
}

Le point d'Ulrich est que puisque vous devez avoir destlen et sourcelen autour (ou les recalculer, ce que fait effectivement strlcat), vous pourriez tout aussi bien utiliser le plus efficace memcpy de toute façon:

if (destlen + sourcelen > dest_maxlen)
{
    goto error_out;
}
memcpy(dest + destlen, source, sourcelen + 1);
destlen += sourcelen;

(Dans le code ci-dessus, dest_maxlen est la longueur maximale de la chaîne qui peut être stockée dans dest - une de moins que la taille du tampon dest. dest_bufferlen est la taille complète du dest buffer).

30
caf

Quand les gens disent, "strcpy() est dangereux, utilisez strncpy() à la place" (ou des déclarations similaires sur strcat() etc., mais je vais utiliser strcpy() ici comme point de mire), ils signifient qu'il n'y a pas de bornes vérifiant strcpy(). Ainsi, une chaîne trop longue entraînera des dépassements de tampon. Ils sont corrects. L'utilisation de strncpy() dans ce cas empêchera les dépassements de tampon.

Je pense que strncpy() ne résout vraiment pas les bugs: il résout un problème qui peut être facilement évité par un bon programmeur.

En tant que programmeur C, vous devez connaître la taille de destination avant d'essayer de copier des chaînes. C'est l'hypothèse des derniers paramètres de strncpy() et strlcpy(): vous leur fournissez cette taille. Vous pouvez également connaître la taille de la source avant de copier des chaînes. Ensuite, si la destination n'est pas assez grande, n'appelez pas strcpy(). Réallouez le tampon ou faites autre chose.

Pourquoi je n'aime pas strncpy()?

  • strncpy() est une mauvaise solution dans la plupart des cas: votre chaîne va être tronquée sans aucun préavis. Je préfère écrire du code supplémentaire pour le comprendre moi-même et ensuite suivre la ligne de conduite que je veux prendre, plutôt que de laisser une fonction décider pour moi de quoi faire.
  • strncpy() est très inefficace. Il écrit dans chaque octet du tampon de destination. Vous n'avez pas besoin de ces milliers de '\0' À la fin de votre destination.
  • Il n'écrit pas de terminaison '\0' Si la destination n'est pas assez grande. Vous devez donc le faire vous-même de toute façon. La complexité de faire cela ne vaut pas la peine.

Maintenant, nous arrivons à strlcpy(). Les changements de strncpy() le rendent meilleur, mais je ne sais pas si le comportement spécifique de strl* Justifie leur existence: ils sont beaucoup trop spécifiques. Vous devez encore connaître la taille de la destination. Il est plus efficace que strncpy() car il n'écrit pas nécessairement dans chaque octet de la destination. Mais cela résout un problème qui peut être résolu en faisant: *((char *)mempcpy(dst, src, n)) = 0;.

Je ne pense pas que quiconque dise que strlcpy() ou strlcat() peut entraîner des problèmes de sécurité, ce qu'ils (et moi) disent qu'ils peuvent entraîner des bugs, par exemple, lorsque vous vous attendez la chaîne complète à écrire au lieu d'une partie de celle-ci.

Le problème principal ici est: combien d'octets à copier? Le programmeur doit le savoir et s'il ne le sait pas, strncpy() ou strlcpy() ne le sauvera pas.

strlcpy() et strlcat() ne sont pas standard, ni ISO C ni POSIX. Ainsi, leur utilisation dans des programmes portables est impossible. En fait, strlcat() a deux variantes différentes: l'implémentation Solaris est différente des autres pour les cas Edge impliquant une longueur 0. Cela la rend encore moins utile qu'autrement.

20
Alok Singhal

Je pense qu'Ulrich et d'autres pensent que cela donnera un faux sentiment de sécurité. Des chaînes tronquées accidentellement peut ont des implications de sécurité pour d'autres parties du code (par exemple, si un chemin d'accès au système de fichiers est tronqué, le programme peut ne pas effectuer d'opérations sur le fichier prévu).

11
jamesdlin

Je ne pense pas que strlcpy et strlcat soient considérés comme peu sûrs ou du moins ce n'est pas la raison pour laquelle ils ne sont pas inclus dans la glibc - après tout, la glibc inclut strncpy et même strcpy.

La critique qu'ils ont reçue est qu'ils sont prétendument inefficaces, pas précaires .

Selon le Secure Portability papier de Damien Miller:

Les API strlcpy et strlcat vérifient correctement les limites du tampon cible, nul-terminate dans tous les cas et renvoient la longueur de la chaîne source, permettant la détection de la troncature. Cette API a été adoptée par la plupart des systèmes d'exploitation modernes et de nombreux progiciels autonomes, notamment OpenBSD (d'où elle provient), Sun Solaris, FreeBSD, NetBSD, le noyau Linux, rsync et le projet GNOME. L'exception notable est la GNU, glibc [12], dont le responsable refuse résolument d'inclure ces API améliorées, les étiquetant "merde BSD horriblement inefficace" " [4], malgré la preuve préalable qu'ils sont plus rapides dans la plupart des cas que les API qu'ils remplacent [13]. Par conséquent, plus de 100 des packages logiciels présents dans l'arborescence des ports OpenBSD maintiennent leurs propres remplacements strlcpy et/ou strlcat ou API équivalentes - ce n'est pas une situation idéale.

C'est pourquoi ils ne sont pas disponibles dans la glibc, mais ce n'est pas vrai qu'ils ne sont pas disponibles sur Linux. Ils sont disponibles sur Linux dans libbsd:

Ils sont empaquetés dans Debian et Ubuntu et dans d'autres distributions. Vous pouvez également récupérer une copie et l'utiliser dans votre projet - c'est court et sous une licence permissive:

4
rsp

La sécurité n'est pas un booléen. Les fonctions C ne sont pas totalement "sécurisées" ou "non sécurisées", "sûres" ou "dangereuses". Lorsqu'elle est utilisée de manière incorrecte, une simple opération d'affectation en C peut être "non sécurisée". strlcpy () et strlcat () peuvent être utilisés en toute sécurité (en toute sécurité) tout comme strcpy () et strcat () peuvent être utilisés en toute sécurité lorsque le programmeur fournit les assurances nécessaires d'une utilisation correcte.

Le point principal avec toutes ces fonctions de chaîne C, standard et pas si standard, est le niveau auquel elles font une utilisation sûre/sécurisée facile. strcpy () et strcat () ne sont pas triviaux à utiliser en toute sécurité; cela est prouvé par le nombre de fois où les programmeurs C se sont trompés au fil des ans et des vulnérabilités et des exploits désagréables se sont ensuivis. strlcpy () et strlcat () et d'ailleurs, strncpy () et strncat (), strncpy_s () et strncat_s (), sont un bit plus facile à utiliser en toute sécurité, mais non trivial. Sont-ils dangereux/peu sûrs? Pas plus que memcpy (), lorsqu'il n'est pas utilisé correctement.

1
rswindell