viernes, 18 de mayo de 2007

Sobre str*cpy() y str*cat()

Es bien conocido por los programadores de C los problemas de seguridad asociados a las funciones strcpy() y strcat(). El hecho de que no verifiquen la longitud de los datos que se estan copiando da origen a graves desbordamientos de buffer. Para evitar este problema se suelen usar las funciones strncpy() y strncat() respectivamente. Ambas, copian únicamente el número de bytes especificados. Aunque esto representa una mejora considerable sobre strcpy() y strcat() continua existiendo un problema. Si se sobrepasa el tamaño máximo en la copia, estas funciones no finalizan el string en NULL. Veamos un ejemplo de lo que pasa:


int main()
{
char a[32];
char b[8];
char *c = "aaaaaaaa";

strcpy(a, "informacion sensible");
strncpy(b, c, 8);

printf("%s\n", b);

return 0;
}



Si ejecutamos este código, la lógica nos dice que el resultado debería ser:
aaaaaaaa


Sin embargo, dado que strncpy() no pone un null al final por haber sobrepasado la lóngitud máxima (en este caso 8), el resultado será:

aaaaaaaainformacion sensible


dando lugar a un fallo de seguridad.


Para evitar este tipo de problemas existen dos opciones. La primera consiste en asegurarnos de que se pone un NULL al final del string. Por ejemplo añadiendo:
b[7]=0;


La sengunda consiste en usar funciones seguras como strlcpy() y strlcat(). Pero estas funciones no son estándar, así que no suelen estar en algunos sistemas (como por ejemplo GNU/Linux). Así que a continuación dejo una copia:


void strlcpy(char *dst, char *src, size_t size)
{
size_t len = size;
char*  dstptr = dst;
char*  srcptr = src;

if(len && --len)
do { if(!(*dstptr++ = *srcptr++)) break; } while(--len);

if (!len && size) *dstptr=0;
}




void strlcat(char *dst, char *src, size_t size)
{
size_t len = size;
size_t dstlen;
char *dstptr = dst;
char *srcptr = src;

while(len-- && *dstptr)
dstptr++;

dstlen = dstptr-dst;

if(!(len=size-dstlen))
return;

while(*srcptr)
{
if(len!=1)
{
*dstptr++ = *srcptr;
len--;
}
srcptr++;
}
*dstptr=0;
}

No hay comentarios: