En primer lugar, strlcpy
nunca se ha pensado como una versión segura de strncpy
(y strncpy
nunca se ha pensado como una versión segura de strcpy
). Estas dos funciones no están relacionadas en absoluto. strncpy
es una función que no tiene ninguna relación con las cadenas C (es decir, cadenas terminadas en nulo). El hecho de que tenga el str...
prefijo en su nombre es solo un error histórico. La historia y el propósito de strncpy
son bien conocidos y están bien documentados. Esta es una función creada para trabajar con las llamadas cadenas de "ancho fijo" (no con cadenas C) utilizadas en algunas versiones históricas del sistema de archivos Unix. Algunos programadores de hoy se confunden con su nombre y asumen questrncpy
alguna manera se supone que sirve como una función de copia de cadena C de longitud limitada (un hermano "seguro" destrcpy
), que en realidad es una completa tontería y conduce a una mala práctica de programación. La biblioteca estándar de C en su forma actual no tiene ninguna función para la copia de cadena C de longitud limitada. Aquí es donde strlcpy
encaja. De strlcpy
hecho, es una verdadera función de copia de longitud limitada creada para trabajar con C-strings. strlcpy
hace correctamente todo lo que debería hacer una función de copia de longitud limitada. La única crítica que se le puede hacer es que, lamentablemente, no es estándar.
En segundo lugar, strncat
por otro lado, es de hecho una función que trabaja con C-strings y realiza una concatenación de longitud limitada (de hecho es un hermano "seguro" de strcat
). Para utilizar esta función correctamente el programador debe tener un cuidado especial, ya que el parámetro de tamaño que acepta esta función no es realmente el tamaño del búfer que recibe el resultado, sino el tamaño de su parte restante (también, el carácter terminador se cuenta implícitamente). Esto puede resultar confuso, ya que para vincular ese tamaño con el tamaño del búfer, el programador debe recordar realizar algunos cálculos adicionales, que a menudo se utilizan para criticar elstrncat
.strlcat
se encarga de estos problemas, cambiando la interfaz para que no sean necesarios cálculos adicionales (al menos en el código de llamada). Nuevamente, la única base que veo que uno puede criticar es que la función no es estándar. Además, las funciones de strcat
grupo es algo que no verá en el código profesional muy a menudo debido a la facilidad de uso limitada de la idea misma de la concatenación de cadenas basada en reexploración.
En cuanto a cómo estas funciones pueden provocar problemas de seguridad ... Simplemente no pueden. No pueden provocar problemas de seguridad en mayor medida de lo que el propio lenguaje C puede "provocar problemas de seguridad". Verá, durante bastante tiempo hubo un fuerte sentimiento de que el lenguaje C ++ tiene que moverse en la dirección de convertirse en un sabor extraño de Java. Este sentimiento a veces también se derrama en el dominio del lenguaje C, lo que resulta en una crítica bastante desorientada y forzada de las características del lenguaje C y las características de la biblioteca estándar C. Sospecho que podríamos estar lidiando con algo así en este caso también, aunque seguramente espero que las cosas no estén tan mal.
strlcpy
ystrlcat
reportaría algún tipo de condición de error si chocaran con el límite de tamaño del búfer de destino. Aunque puede verificar la longitud devuelta para probar esto, no es obvio. Pero creo que es una crítica menor. El argumento de 'fomentan el uso de cadenas C, por lo que son malas' es una tontería.strcpy
está por encima del umbral y por lo tanto "inseguridad", y su función de cadena de copia preferido (si esstrlcpy
,strcpy_s
o inclusostrncpy
) está por debajo del umbral y por lo tanto "seguro".strlcpy/strlcat
. A uno le podría "disgustar" el concepto general de cadena terminada en cero, pero de eso no se trata la pregunta. Si conoce "muchas razones para que nostrlcpy/strlcat
me guste ", probablemente debería escribir su propia respuesta en lugar de esperar que pueda leer la mente de otra persona.strlcpy/strlcat
. Aunque creo que entiendo de qué se trata, personalmente me niego a reconocerlo como "problemas de seguridad" dentro del ámbito del lenguaje C tradicional, tal como lo conozco. Eso lo dije en mi respuesta.La crítica de Ulrich se basa en la idea de que un truncamiento de cadena que no es detectado por el programa puede generar problemas de seguridad, debido a una lógica incorrecta. Por lo tanto, para estar seguro, debe verificar el truncamiento. Hacer esto para una concatenación de cadenas significa que está haciendo una verificación a lo largo de las líneas de esto:
if (destlen + sourcelen > dest_maxlen) { /* Bug out */ }
Ahora,
strlcat
haga esta verificación de manera efectiva, si el programador recuerda verificar el resultado, para que pueda usarlo de manera segura:if (strlcat(dest, source, dest_bufferlen) >= dest_bufferlen) { /* Bug out */ }
El punto de Ulrich es que dado que tienes que tener
destlen
ysourcelen
alrededor (o recalcularlos, que es lo questrlcat
efectivamente hace), también podrías usar el más eficiente dememcpy
todos modos:if (destlen + sourcelen > dest_maxlen) { goto error_out; } memcpy(dest + destlen, source, sourcelen + 1); destlen += sourcelen;
(En el código anterior,
dest_maxlen
es la longitud máxima de la cadena en la que se puede almacenardest
, uno menos que el tamaño deldest
búfer.dest_bufferlen
Es el tamaño completo deldest buffer
).fuente
memcpy
él puede ser cualquier tipo de memoria y tengo una dimensión suplementaria para comprobar cuando intento entender el código. Tenía una aplicación heredada para depurar donde todo se hacía con memcpy, era un PITA real para corregir. Después de la migración a la función String dedicada, es mucho más fácil de leer (y más rápido porquestrlen
se pueden eliminar muchas cosas innecesarias ).memcpy()
es suficiente (y potencialmente más eficiente questrcpy()
).memcpy()
es una operación de cadena<string.h>
; después de todo, está declarada .Cuando la gente dice "
strcpy()
es peligroso, utilícelostrncpy()
en su lugar" (o declaraciones similares sobrestrcat()
etc., pero lo voy a usarstrcpy()
aquí como mi enfoque), quieren decir que no hay límitesstrcpy()
. Por lo tanto, una cadena demasiado larga resultará en saturaciones de búfer. Son correctos. El usostrncpy()
en este caso evitará desbordamientos del búfer.Siento que
strncpy()
realmente no soluciona errores: resuelve un problema que un buen programador puede evitar fácilmente.Como programador de C, debe conocer el tamaño de destino antes de intentar copiar cadenas. Esa es la premisa de
strncpy()
ystrlcpy()
's últimos parámetros demasiado: Usted suministro de ese tamaño a ellos. También puede conocer el tamaño de la fuente antes de copiar cadenas. Entonces, si el destino no es lo suficientemente grande, no llamestrcpy()
. Reasigne el búfer o haga otra cosa.¿Por qué no me gusta
strncpy()
?strncpy()
es una mala solución en la mayoría de los casos: su cadena se truncará sin previo aviso; prefiero escribir código adicional para resolver esto yo mismo y luego tomar el curso de acción que quiero tomar, en lugar de dejar que alguna función decida yo sobre qué hacer.strncpy()
es muy ineficiente. Escribe en cada byte del búfer de destino. No necesita esos miles'\0'
al final de su destino.'\0'
si el destino no es lo suficientemente grande. Por lo tanto, debe hacerlo usted mismo de todos modos. La complejidad de hacer esto no vale la pena.Ahora llegamos a
strlcpy()
. Los cambios de lostrncpy()
hacen mejor, pero no estoy seguro de si el comportamiento específico destrl*
justifica su existencia: son demasiado específicos. Aún tienes que conocer el tamaño del destino. Es más eficiente questrncpy()
porque no escribe necesariamente en cada byte del destino. Pero los que resuelve un problema que puede ser resuelto haciendo:*((char *)mempcpy(dst, src, n)) = 0;
.No creo que nadie diga eso
strlcpy()
ostrlcat()
pueda dar lugar a problemas de seguridad, lo que ellos (y yo) estamos diciendo que puede resultar en errores, por ejemplo, cuando espera que se escriba la cadena completa en lugar de una parte de ella.El problema principal aquí es: ¿cuántos bytes copiar? El programador debe saber esto y si no lo sabe,
strncpy()
ostrlcpy()
no lo salvará.strlcpy()
ystrlcat()
no son estándar, ni ISO C ni POSIX. Entonces, su uso en programas portátiles es imposible. De hecho,strlcat()
tiene dos variantes diferentes: la implementación de Solaris es diferente de las otras para los casos de borde que involucran la longitud 0. Esto la hace aún menos útil que de otra manera.fuente
strlcpy
es más rápido quememcpy
en muchas arquitecturas, especialmente simemcpy
copia datos finales innecesarios.strlcpy
también devuelve la cantidad de datos que perdió, lo que podría permitirle una recuperación más rápida y con menos código.n
en mi llamada de memcpy está el número exacto de bytes que se escribirán, por lo que la eficiencia tampoco es un gran problema.strlcpy
cada vez que lo necesitememcpy
ystrlen
eso también está bien, pero entonces, ¿por qué detenerse enstrlcpy
? Tampoco necesita unamemcpy
función, puede copiar los bytes uno por uno. La implementación de referencia solo recorre los datos una vez en el caso normal y eso es mejor para la mayoría de las arquitecturas. Pero incluso si se utiliza la mejor implementaciónstrlen
+memcpy
, todavía no hay razón para no tener que volver a implementar una strcpy segura una y otra vez.strlcpy
usted barre la cadena de entrada solo una vez en el caso bueno (que debería ser la mayoría) y dos veces en el caso malo, con sustrlen
+memcpy
lo revisa dos veces siempre. Si marca la diferencia en la práctica, es otra historia.Creo que Ulrich y otros creen que les dará una falsa sensación de seguridad. Truncar cadenas accidentalmente puede tener implicaciones de seguridad para otras partes del código (por ejemplo, si se trunca una ruta del sistema de archivos, es posible que el programa no esté realizando operaciones en el archivo deseado).
fuente
malware.exe.jpg
amalware.exe
.Hay dos "problemas" relacionados con el uso de funciones strl:
Los redactores de borradores estándar c1x y Drepper, argumentan que los programadores no verificarán el valor de retorno. Drepper dice que de alguna manera deberíamos conocer la longitud y usar memcpy y evitar las funciones de cadena por completo. El comité de estándares argumenta que la strcpy segura debería devolver un valor distinto de cero en el truncamiento a menos que la
_TRUNCATE
bandera indique lo contrario . La idea es que es más probable que las personas usen if (strncpy_s (...)).Algunas personas piensan que las funciones de cadena nunca deberían fallar incluso cuando se alimentan con datos falsos. Esto afecta a funciones estándar como strlen, que en condiciones normales se producirán por defecto. El nuevo estándar incluirá muchas de estas funciones. Los controles, por supuesto, tienen una penalización de rendimiento.
La ventaja de las funciones estándar propuestas es que puede saber cuántos datos perdió con las funciones strl .
fuente
strncpy_s
no es una versión segurastrncpy
sino básicamente unstrlcpy
reemplazo.No pienso
strlcpy
y mestrlcat
consideran inseguro o menos no es la razón por la que no están incluidos en glibc - después de todo, glibc incluye strncpy e incluso strcpy.Las críticas que recibieron fue que supuestamente son ineficientes, no inseguros. .
Según el documento Secure Portability de Damien Miller:
Por eso no están disponibles en glibc, pero no es cierto que no estén disponibles en Linux. Están disponibles en Linux en libbsd:
Están empaquetados en Debian y Ubuntu y otras distribuciones. También puede simplemente tomar una copia y usarla en su proyecto; es breve y está bajo una licencia permisiva:
fuente
La seguridad no es un booleano. Las funciones de C no son totalmente "seguras" o "inseguras", "seguras" o "inseguras". Cuando se usa incorrectamente, una simple operación de asignación en C puede ser "insegura". strlcpy () y strlcat () se pueden utilizar de forma segura (de forma segura) del mismo modo que strcpy () y strcat () se pueden utilizar de forma segura cuando el programador proporciona las garantías necesarias de un uso correcto.
El punto principal de todas estas funciones de cadena C, estándar y no tan estándar, es el nivel al que hacen un uso seguro / seguro fácil . strcpy () y strcat () no son triviales para usar de forma segura; esto se demuestra por la cantidad de veces que los programadores de C se han equivocado a lo largo de los años y se han producido vulnerabilidades y exploits desagradables. strlcpy () y strlcat () y para el caso, strncpy () y strncat (), strncpy_s () y strncat_s (), son un poco más fáciles de usar de forma segura, pero aún así, no triviales. ¿Son inseguros / inseguros? No más de lo que es memcpy (), cuando se usa incorrectamente.
fuente