
figura
Sé que es posible desbordar el código ordinario:
cadena de caracteres[9];
scanf(“%s”, cadena).
Pero, ¿es posible desbordar scanf(“%8s”, cadena)? 8 es solo un ejemplo.
Sé que “%8s” funciona como un límite, pero también noto que cuando ingreso una cadena de más de 8 caracteres, el programa se cerrará debido a:
* Rotura de pila detectada *: ./a.out terminado
======= Seguimiento: =========
…
Obviamente, hay un indicador que detecta la destrucción de pila activada por GCC de forma predeterminada. Dado que se trata de una destrucción de pila, supongo que todavía es posible desbordarse y ejecutar código arbitrario.
Contrariamente al desbordamiento normal que destroza a la persona que llama de scanf(“%s”), si scanf(“%8s”) puede desbordarse, se desbordará dentro de la función scanf para que cuando scanf intente regresar, se obtenga el control.
Pero scanf es una llamada al sistema que requiere un cambio de modo (cambiar del modo de usuario al modo kernel), e internamente llamará a cosas como leer en el stdin, etc. Así que no estoy seguro de si podemos desbordar en modo kernel o algo así.
Los comentarios son bienvenidos!!
ACTUALIZAR >>
cadena de caracteres[9] se supone en el ejemplo anterior. cadena de caracteres[8] siguiendo código real.
La pregunta es realmente sobre la historia aparentemente conflictiva entre el escaneo seguro (“%8s”) y el aborto de GCC debido a la destrucción de la pila.
Código simplificado:
void foo(pass some pointer) {
char input[8];
int input_number = 0;
while (1) { // looping console
printf some info;
scanf("%8s", input);
input_number = atoi(input);
if ((strlen(input) == 1) && (strncmp(input, "q", 1) == 0)) {
input_number = -1;
}
switch (input_number) {
case -1: to quit the console if input="q";
default: to print info that pointer refers to;
...
}
}
}
Nota:
- foo es llamado por otra persona.
- Aunque la cadena es de 8 bytes en código real con “% 8s”, no creo que esto conduzca a romper.

ysth
Ver http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html:
Cada directiva se compone de uno de los siguientes… Un entero decimal opcional distinto de cero que especifica el ancho máximo del campo.
s
Coincide con una secuencia de bytes que no son caracteres de espacio en blanco. La aplicación se asegurará de que el argumento correspondiente sea un puntero al byte inicial de una matriz de caracteres, caracteres con signo o caracteres sin signo lo suficientemente grandes como para aceptar la secuencia y un código de carácter nulo de terminación, que se agregará automáticamente.
Por lo tanto, no desbordará un búfer de cadena de 9 bytes.

paxdiablo
no siempre utilizar scanf
(o fscanf
para el caso) si desea que su entrada sea sólida.
deberías estar usando fgets
(o una variante similar “protegida contra el desbordamiento del búfer”) luego use sscanf
en ese.
El principal problema con scanf
y fscanf
es que su puntero de archivo puede terminar en una posición indeterminada si la línea no tiene el formato esperado (es decir, si el scanf
falla). Con el fgets/sscanf
método, es mucho más fácil garantizar que estás en un límite de línea, sin tener que usar ftell
y fseek
para moverse por el archivo.
Con respecto a su consulta específica sobre si el búfer se desbordará, el estándar C dice lo siguiente:
… el argumento correspondiente será un puntero al elemento inicial de una matriz de caracteres lo suficientemente grande como para aceptar la secuencia y un carácter nulo de terminación, que se agregará automáticamente.
Entonces, para un "%8s"
formato, necesita una matriz de 9 caracteres.
Sospecho que tienes algún otro problema en tu código. Con un programa de prueba:
#include <stdio.h>
int main(int argc, char* argv[]) {
char x1;
char a[9];
char x2;
x1 = x2 = ' ';
scanf ("%s",a);
printf ("[%c] [%s] [%c]\n",x1,a,x2);
return 0;
}
Yo obtengo:
pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[s] [dfjdhadgha...lghjdfgjhd] [ ]
6 [main] qq 4744 _cygtls::handle_exceptions: Error while dumping state
(probably corrupted stack)
Segmentation fault (core dumped)
Cuando cambio ese mismo programa para usar "%8s"
obtengo (para exactamente la misma entrada):
pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[ ] [dfjdhadg] [ ]
si la cadena se asigna para menos de 8 cartas, ciertamente sobrescribirá el búfer y scanf no agregará un terminador nulo. Pero siempre que tenga suficiente espacio en la cadena para su valor, no debería obtener una exageración.
Como señaló ysth, la matriz debería poder contener la cadena y el carácter nulo de terminación, por lo que es muy probable que el uso de una matriz de 8 bytes (especialmente si está asignado en la pila, como está en su código) lo arruine.
scanf es una función de biblioteca en tiempo de ejecución; no es necesario cambiar de modo ya que opera en el espacio del usuario, a menos que tenga que solicitar el llenado del búfer, en cuyo caso llamaría a read o fread.
– Wallyk
24 de noviembre de 2009 a las 5:18
como se señaló varias veces en las respuestas, se agrega un byte nulo, por lo que necesita un búfer de 9 caracteres para aceptar hasta 8 caracteres de entrada.
– ysth
24 de noviembre de 2009 a las 6:18
Como mucha gente ha señalado, su suposición en la “Nota 2”. Está Mal. Ese ejemplo permite un solo byte de desbordamiento, que es lo que está detectando gcc.
– café
24 de noviembre de 2009 a las 6:49
ustedes tienen razón. Lo probé con un programa aún más simple, pero de alguna manera no falló la última vez que lo intenté. Ahora, cuando ingreso “12345678” para cadena[8] y scanf(%8s) se bloquea debido a la destrucción de la pila. Así que aquí está la lección aprendida. Smashing no significa necesariamente que haya un ataque de desbordamiento de pila.
– Figo
27 de noviembre de 2009 a las 18:45
Aunque el búfer está en la pila en este caso, el error de programación es un desbordamiento del búfer, no un desbordamiento de la pila. Reetiqueté la pregunta en consecuencia.
– Programador de Windows
3 de febrero de 2010 a las 5:53