Desbordamiento sobre scanf(“%8s”, cadena)?

7 minutos de lectura

Desbordamiento sobre scanf8s cadena
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:

  1. foo es llamado por otra persona.
  2. Aunque la cadena es de 8 bytes en código real con “% 8s”, no creo que esto conduzca a romper.

  • 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

Desbordamiento sobre scanf8s cadena
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.

  • Si no se desborda, ¿por qué GCC sigue contando la historia de Stack Smashing?

    – Figo

    24 de noviembre de 2009 a las 5:24

  • @Figo: de alguna manera no estás entendiendo. “%8s” almacenará hasta 9 bytes, por lo que necesita una matriz de nueve caracteres.

    – ysth

    24 de noviembre de 2009 a las 7:48

1646956629 204 Desbordamiento sobre scanf8s cadena
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 lo se. Pero en este momento estoy interesado en saber si scanf(%8s) tiene el mismo problema que scanf, ya que GCC me dice que todavía hay una destrucción de pila.

    – Figo

    24 de noviembre de 2009 a las 5:21

  • Describir “robusto”? ¿Da algunos ejemplos?

    – ysth

    24 de noviembre de 2009 a las 5:23

  • @ysth: (1) Obtenga su entrada como líneas. (2) Asegúrese de obtener líneas completas (\n carácter al final), de lo contrario, error con “línea demasiado larga”. (3) Use sscanf en línea: puede hacer esto tantas veces como quiera en la línea sin preocuparse por el archivo subyacente.

    – pax diablo

    24 de noviembre de 2009 a las 5:28

  • También pruebo un código simplificado similar al que usted hizo y GCC no se quejará de la destrucción de la pila. He publicado el código original y la cosa es en tiempo de ejecución, GCC se quejará cuando ingrese 12345678 (Nota en la cadena de caracteres del código real[8]).

    – Figo

    24 de noviembre de 2009 a las 6:01

  • @Figo, necesita una matriz de 9 caracteres para almacenar una cadena de 8 caracteres. Eso es porque una cadena de 8 caracteres consta de 8 caracteres (obviamente) y un carácter de terminación nulo (no tan obvio). Si lo cambias a char string[9]no deberías tener ningún problema.

    – pax diablo

    24 de noviembre de 2009 a las 12:41

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.

  • Necesitaría al menos 9 bytes para no desbordarse.

    – Wallyk

    24 de noviembre de 2009 a las 5:16

  • De hecho, creo que scanf pondrá un ‘\0’ al final. El estándar C dice “un carácter nulo de terminación, que se agregará automáticamente”, también citado por paxdiablo

    – Figo

    24 de noviembre de 2009 a las 5:33

  • Quise decir si no tuvieras también un espacio para el nulo.

    – volver a ejecutar

    24 de noviembre de 2009 a las 5:43

  • Si no tiene un espacio para el nulo, lo colocará allí de todos modos (sobrescribiendo alguna otra parte de la pila si es necesario).

    – pax diablo

    24 de noviembre de 2009 a las 5:47

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.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad