El típico programa de un buffer overflow en C se da en la siguiente función:
int mi_funcion(char *input){
Si la cadena a la que apunta input es controlada por el usuario y no existe ningún límite en el número de caracteres (ya sea porque estamos leyendo de un fichero en disco, de la red o entrada del usuario vía teclado), al usar la función strcat acabaremos sobrepansando el tamaño de buf, y escribiendo en direcciones de memoria que no se debe. Si el programa donde se da este fallo se ejecuta con privilegios, puede aprovecharse para hacer una escalada desde un usuario normal a otro privilegiado.
char buf[256];
....
....
strcat("CADENA",buf);
....
....
return 0;
}
Lo primero es usar las funciones de la librería estándar de C:strncpy y strncat.
char* strncpy(char *restrict s1, const char *restrict s2, size_t n);El cambio fundamental es es el parámetro n, que especifica el número de bytes del búfer apuntado por s1. Así cualquiera de esas dos funciones copiará como máximo n bytes o bien si encuentra en la cadena que esté copiando, el carácter que manda el fin de cadena en C, el \0.
char* strncat(char *restrict s1, const char *restrict s2, size_t n);
Sin embargo estas dos funciones tienen dos problemas:
- strncpy no termina con el \0 la cadena si se utiliza todo el búfer.
- strncat rellena de ceros todo el búfer de destino hasta el tamaño que se especifica
size_t strlcpy(char *dst, const char *src, size_t size);Estas dos funciones garantizan que las cadenas están terminada con un \0 y permite detectar de manera sencilla en el caso de strlcat la existencia de que una cadena se trunque, como puede verse en este ejemplo sacado de la página de manual de MacOS X:
size_t strlcat(char *dst, const char *src, size_t size);
if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))Las decisiones de diseño que llevaron a estas funciones están descritas en el artículo enlazado al principio. Aunque hace mucho tiempo del artículo, en el año 1999, es una lectura interesante para comprender la evolución de las API para evitar los problemas de seguridad.
goto toolong;
if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
goto toolong;
Actualización
Me comenta mig21 que estas funciones no siempre le han gustado a otros desarrolladores. Por ejemplo, Ulrich Drepper, mantenedor de la GNU libc:This is horribly inefficient BSD crap. Using these function only leads to other errors. Correct string handling means that you always know how long your strings are and therefore you can you memcpy (instead of strcpy).Y es interesante el enlace a la entrada en la wikipedia de strlcpy.
Technorati Tags: buffer overflow, c
3 comentarios:
El uso de strlcpy y strlcat es también polémico (¿Alguien se libra de la polémica? ¿Ni una API para manejar cadenas en C? :)
Bueno, pues Ulrich Drepper, el mantenedor de la glibc no quiso incluirlas en ella porque oculta errores en lugar de mostrarlos. Con esa delicadeza característica de algunos desarrolladores dijo:
This is horribly inefficient BSD crap. Using these function only leads to other errors. Correct string handling means that you always know how long your strings are and therefore you can you memcpy(instead of strcpy).
Beside, those who are using strcat or variants deserved to be punished.
Y otras veces, preguntado por ellas apunta a un artículo interesante, escrito por él, claro, sobre que hacer en caso de que las cosas no vayan bien, en la que se habla de asprintf, que evita el malvado truncado :) (pero que se encarga de alojar memoria que luego habrá que liberar)
Lo que ha ocurrido al final, por cierto, es que, por lo que cuentan en la wiki en inglés, la gente de la Glib, rsync se han implementado su propia versión. También en el kernel Linux lo usan, por cierto.
Por desgracia, el tema de gestión correcta de cadenas en C parece un oximorón. Cualquier API que permita reducir la posibilidad de error siempre es bienvenida.
Ahora actualizo las entradas con los enlaces que has puesto, para el otro punto de vista :)
muy buen articulos. vi que en una parte se declara a un puntero como strict. esto que efecto hace?
Publicar un comentario