87 votes

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ûrs des strncpy et strncat . Cependant, certaines personnes sont encore d'avis qu'elles sont l'insécurité, et simplement causer un autre type de problème .

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 de caractères) peut entraîner des problèmes de sécurité ?

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

118voto

AndreyT Points 139512

Tout d'abord, 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 ne sont absolument pas liées. strncpy est une fonction qui n'a aucune relation avec les chaînes de caractères C (c'est-à-dire les chaînes de caractères à terminaison nulle). Le fait qu'elle ait l'attribut str... dans son nom est juste une erreur historique. L'histoire et le but de strncpy est bien connue et bien documentée. Il s'agit d'une fonction créée pour travailler avec les chaînes de caractères dites "à largeur fixe" (et non avec les chaînes de caractères C) utilisées dans certaines versions historiques du système de fichiers Unix. Certains programmeurs sont aujourd'hui déroutés par son nom et supposent que la fonction strncpy est en quelque sorte censé servir de fonction de copie de chaînes de caractères C de longueur limitée (une sœur "sécurisée" de la fonction strcpy ), ce qui, en réalité, est un non-sens total et conduit à de mauvaises pratiques de programmation. La bibliothèque standard du C, dans sa forme actuelle, n'a aucune fonction pour la copie de chaînes de caractères C de longueur limitée. C'est là que les strlcpy s'adapte. 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 devrait faire. La seule critique que l'on puisse lui adresser est qu'elle n'est, malheureusement, pas standard.

Deuxièmement, strncat d'autre part, est en effet une fonction qui fonctionne avec des chaînes C et effectue une concaténation de longueur limitée (il s'agit en effet d'une fonction "sécurisée" de la fonction strcat ). Pour utiliser cette fonction correctement, le programmeur doit faire preuve d'une attention particulière, car le paramètre size que cette fonction accepte n'est pas vraiment la taille du tampon qui reçoit le résultat, mais plutôt la taille de sa partie restante (de plus, le caractère de terminaison est compté implicitement). Cela peut prêter à confusion, car pour lier cette taille à celle du tampon, le programmeur doit se souvenir d'effectuer quelques calculs supplémentaires, ce qui est souvent utilisé pour critiquer la fonction strncat . strlcat s'occupe de ces questions, en modifiant l'interface de sorte qu'aucun calcul supplémentaire ne soit nécessaire (du moins dans le code d'appel). Encore une fois, la seule critique que l'on puisse formuler à ce sujet est que la fonction n'est pas standard. De plus, les fonctions de strcat est quelque chose que vous ne verrez pas très souvent dans le code professionnel en raison de l'utilité limitée de l'idée même de concaténation de chaînes de caractères basée sur le rescan.

Quant à savoir comment ces fonctions peuvent entraîner des problèmes de sécurité... Elles ne le peuvent tout simplement pas. Elles 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 a eu un fort sentiment que le langage C++ doit évoluer dans la direction d'une sorte de saveur bizarre de Java. Ce sentiment se répand parfois dans le domaine du langage C également, ce qui donne lieu à des critiques plutôt maladroites et forcées des caractéristiques du langage C et de la bibliothèque standard C. Je soupçonne que nous pourrions avoir affaire à quelque chose de ce genre dans ce cas également, même si j'espère vraiment que les choses ne sont pas si mauvaises.

10 votes

Je ne suis pas tout à fait d'accord. Ce serait bien si strlcpy et strlcat signaleraient une sorte d'erreur s'ils se heurtaient à la taille limite du tampon de destination. Bien que vous puissiez vérifier la longueur retournée pour tester cela, ce n'est pas évident. Mais je pense que c'est une critique mineure. L'argument "ils encouragent l'utilisation de chaînes de caractères C, et donc ils sont mauvais" est stupide.

7 votes

"comment ces fonctions peuvent conduire à des problèmes de sécurité" - Pour info, je pense que le problème ici est que certaines fonctions C sont plus difficiles à utiliser correctement que d'autres. Certaines personnes croient à tort qu'il existe un seuil de difficulté particulier, en dessous duquel une fonction est "sûre" et au-dessus duquel elle est "non sûre". Ces personnes croient aussi généralement que strcpy est supérieure au seuil et donc "non sécurisée", et leur fonction préférée de copie de chaîne (qu'elle soit strlcpy , strcpy_s ou même strncpy ) est inférieur au seuil et donc "sûr".

1 votes

Bien sûr, il y a quelques fonctions (comme gets ) qui sont en fait impossible à utiliser correctement, et peuvent donc raisonnablement être qualifiés d'"insécurisés" sans avoir à préciser ce qui l'est :-)

32voto

caf Points 114951

La critique d'Ulrich repose sur l'idée qu'une troncature de chaîne non détectée par le programme peut entraîner des problèmes de sécurité, par le biais d'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 de caractères signifie que vous effectuez une vérification du type de celle-ci :

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

Maintenant, strlcat effectue effectivement cette vérification, si le programmeur n'oublie pas de vérifier le résultat - donc vous peut l'utiliser en toute sécurité :

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

Le point de vue d'Ulrich est que puisque vous devez avoir destlen et sourcelen (ou de les recalculer, ce qui est ce que fait l'UE). strlcat ), vous pouvez tout aussi bien utiliser la méthode plus efficace de la 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 de caractères qui peut être stockée dans le fichier dest - un de moins que la taille de la dest tampon. dest_bufferlen est la taille complète de la dest buffer ).

15 votes

La lisibilité du code de Drepper est mauvaise. Avec strlcpy (ou n'importe quelle fonction str), je sais directement que je copie une chaîne C terminée par 0. Avec memcpy il peut s'agir de n'importe quel type de mémoire et j'ai une dimension supplémentaire à vérifier lorsque j'essaie de comprendre le code. J'avais une ancienne application à déboguer où tout était fait avec memcpy, c'était un vrai PITA à corriger. Après le portage vers une fonction String dédiée, le code est beaucoup plus facile à lire (et plus rapide parce que beaucoup d'opérations inutiles sont effectuées avec la fonction String). strlen pourrait être supprimée).

0 votes

Pourquoi n'utiliseriez-vous pas simplement strcpy au lieu de memcpy dans le dernier exemple ?

4 votes

@domen : Parce que la taille à copier est déjà connue, donc memcpy() est suffisante (et est potentiellement plus efficace que strcpy() ).

22voto

Alok Singhal Points 33073

Quand les gens disent, " strcpy() est dangereux, utilisez strncpy() au lieu de" (ou des déclarations similaires sur strcat() etc., mais je vais utiliser strcpy() ici comme mon point de mire), ils signifient qu'il n'y a pas de vérification des limites dans strcpy() . Ainsi, une chaîne trop longue entraînera un dépassement de la mémoire tampon. Ils sont corrects. Utilisation de strncpy() dans ce cas, empêchera les dépassements de tampon.

J'ai l'impression que strncpy() ne corrige pas vraiment les bugs : il résout un problème qui peut être facilement évité par un bon programmeur.

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

Pourquoi je n'aime pas strncpy() ?

  • strncpy() est une mauvaise solution dans la plupart des cas : votre chaîne de caractères va être tronquée sans que vous le sachiez. Je préfère écrire du code supplémentaire pour déterminer moi-même ce qu'il en est et ensuite prendre la décision que je souhaite prendre, plutôt que de laisser une fonction décider pour moi de ce qu'il faut faire.
  • strncpy() est très inefficace. Il écrit sur 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 une terminaison '\0' si la destination n'est pas assez grande. Vous devez donc de toute façon le faire vous-même. La complexité de cette opération n'en vaut pas la peine.

Maintenant, nous en arrivons à strlcpy() . Les changements de strncpy() l'améliorer, mais je ne suis pas sûr que le comportement spécifique des strl* justifie leur existence : ils sont beaucoup trop spécifiques. Il faut toujours connaître la taille de la destination. C'est plus efficace que strncpy() parce qu'il n'écrit pas nécessairement sur chaque octet de la destination. Mais il résout un problème qui peut être résolu en faisant : *((char *)mempcpy(dst, src, n)) = 0; .

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

La question principale ici est : combien d'octets faut-il 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. Leur utilisation dans des programmes portables est donc impossible. En effet, strlcat() a deux variantes différentes : l'implémentation de Solaris est différente des autres pour les cas limites impliquant la longueur 0. Cela le rend encore moins utile qu'autrement.

3 votes

strlcpy est plus rapide que memcpy sur de nombreuses architectures, surtout si le memcpy copie les données de queue inutiles. strlcpy renvoie également la quantité de données manquées, ce qui peut vous permettre de récupérer plus rapidement et avec moins de code.

1 votes

@jbcreix : mon point de vue est qu'il ne devrait pas y avoir de données à manquer, et n dans mon appel memcpy est le nombre exact d'octets à écrire, donc l'efficacité n'est pas non plus un problème.

6 votes

Et comment obtenir ce n ? Le seul n que vous pouvez connaître à l'avance est la taille du tampon. Bien sûr, si vous suggérez d'implémenter strlcpy chaque fois que vous en avez besoin en utilisant memcpy et strlen c'est bien aussi, mais alors pourquoi s'arrêter à strlcpy vous ne le faites pas. besoin de a memcpy soit, vous pouvez copier les octets un par un. L'implémentation de référence ne boucle sur les données qu'une seule fois dans le cas normal et c'est mieux pour la plupart des architectures. Mais même si la meilleure implémentation utilisait strlen + memcpy mais ce n'est toujours pas une raison pour ne pas avoir à réimplémenter un strcpy sécurisé encore et encore.

12voto

jamesdlin Points 13455

Je pense qu'Ulrich et d'autres pensent que ça va donner un faux sentiment de sécurité. Troncature accidentelle des chaînes de caractères peut ont des implications en matière 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).

8 votes

Par exemple, un client de messagerie peut tronquer le nom de fichier d'une pièce jointe d'un courriel de la manière suivante malware.exe.jpg à malware.exe .

1 votes

@ChrisPeterson C'est pourquoi un bon développeur vérifie toujours les valeurs de retour, pour, dans le cas des fonctions strl*, savoir si les données ont été tronquées et agir en conséquence.

0 votes

"Ulrich et d'autres pensent que cela donnera un faux sentiment de sécurité....". - Lol... pendant ce temps, Ulrich et ses amis font des apparitions régulières sur BugTraq et Full Disclosure pour leurs actions ponctuelles. Ils devraient utiliser les fonctions les plus sûres et éviter la plupart de leurs problèmes. Ensuite, ils pourront commencer à dire aux autres comment écrire du code plus sûr...

7voto

jbcreix Points 2383

Il existe deux "problèmes" liés à l'utilisation des fonctions strl :

  1. Vous devez vérifier les valeurs de retour pour éviter la troncature.

Les rédacteurs du projet de norme c1x et Drepper, soutiennent que les programmeurs ne vérifieront pas la valeur de retour. Drepper dit que nous devrions d'une manière ou d'une autre connaître la longueur, utiliser memcpy et éviter complètement les fonctions de chaîne de caractères. Le comité de normalisation soutient que la fonction sécurisée strcpy devrait retourner une valeur non nulle en cas de troncature, sauf indication contraire de l'utilisateur. _TRUNCATE drapeau. L'idée est que les gens sont plus susceptibles d'utiliser if(strncpy_s(...)).

  1. Ne peut pas être utilisé sur des non-strings.

Certaines personnes pensent que les fonctions de chaîne de caractères ne devraient jamais se planter, même lorsqu'elles reçoivent des données erronées. Cela affecte les fonctions standard telles que strlen qui, dans des conditions normales, se planteront. La nouvelle norme comprendra de nombreuses fonctions de ce type. Les contrôles ont bien sûr un impact sur les performances.

L'avantage par rapport aux fonctions standard proposées est que vous pouvez savoir combien de données vous avez manqué avec strl fonctions.

0 votes

Notez que strncpy_s n'est pas une version sécurisée de strncpy mais fondamentalement un strlcpy remplacement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X