2009-08-28 12 views
151

Estoy ejecutando mi archivo a.out. Después de la ejecución del programa se ejecuta desde hace algún tiempo y después se salga con el mensaje:Detección de pila detectada

**** stack smashing detected ***: ./a.out terminated* 
*======= Backtrace: =========* 
*/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)Aborted* 

Cuáles podrían ser las posibles razones para esto y cómo puedo corregirlo?

+1

¿Podría identificar qué partes de su código hacen que la pila se rompa y lo publique? Entonces, probablemente podamos señalar exactamente por qué sucede y cómo corregirlo. –

Respuesta

225

Stack Smashing aquí en realidad se debe a un mecanismo de protección utilizado por gcc para detectar errores de desbordamiento de búfer. Por ejemplo, en el siguiente fragmento:

#include <stdio.h> 

void func() 
{ 
    char array[10]; 
    gets(array); 
} 

int main(int argc, char **argv) 
{ 
    func(); 
} 

El compilador, (en este caso gcc) añade las variables de protección (llamados canarios) que tienen valores conocidos. Una cadena de entrada de tamaño superior a 10 causa corrupción de esta variable, lo que hace que SIGABRT finalice el programa.

Para obtener información, puede intentar deshabilitar esta protección de gcc utilizando la opción -fno-stack-protector durante la compilación. En ese caso, obtendrá un error diferente, muy probablemente un error de segmentación, ya que está tratando de acceder a una ubicación de memoria ilegal. Tenga en cuenta que -fstack-protector siempre debe estar activado para compilaciones de lanzamiento, ya que es una característica de seguridad.

Puede obtener información sobre el punto de desbordamiento ejecutando el programa con un depurador. Valgrind no funciona bien con errores relacionados con la pila, pero al igual que un depurador, puede ayudarlo a identificar la ubicación y el motivo del bloqueo.

+2

gracias por esta respuesta!Encontré que en mi caso no había inicializado la variable que estaba tratando de escribir en –

+3

Valgrind no funciona bien para errores relacionados con la pila, ya que no puede agregar zonas rojas allí –

+5

Esta respuesta es incorrecta y proporciona consejos peligrosos . En primer lugar, eliminar el protector de pila no es la solución correcta: si obtiene un error de destrucción de pila, probablemente tenga una vulnerabilidad de seguridad grave en su código. La respuesta correcta es * corregir el código de error *. Segundo, como señala grasGendarme, la recomendación de probar Valgrind no será efectiva. Valgrind normalmente no funciona para detectar accesos a memoria ilegales a datos asignados por pila. –

7

Se podría tratar de depurar el problema utilizando valgrind:

La distribución Valgrind Actualmente incluye seis herramientas de calidad de producción: un detector de error de memoria, dos hilo detectores de errores, una memoria caché y la rama- prediction profiler, call-graph que genera el perfilador de caché, y un perfilador de montón. También incluye dos herramientas experimentales: un montón/stack/global saturación detector, y un bloque básico SimPoint vector generador. Se ejecuta en las siguientes plataformas : X86/Linux, AMD64/Linux, PPC32/Linux, PPC64/Linux, y X86/Darwin (Mac OS X).

+2

Sí, pero Valgrind no funciona bien para desbordamientos de búferes asignados a la pila, que es la situación que indica este mensaje de error. –

+3

¿Cómo podríamos usar ese detector * stack array overrun *? ¿Puedes elaborar? –

3

Significa que escribió algunas variables en la pila de forma ilegal, muy probablemente como resultado de un Buffer overflow.

+9

Desbordamiento de pila es la pila que se estrella contra otra cosa. Aquí es al revés: algo se ha estrellado en la pila. –

+5

No realmente. Es una parte de la pila chocando contra otra parte. Entonces, realmente es un desbordamiento de búfer, simplemente no sobre la parte superior de la pila, sino "solo" en otra parte de la pila. –

13

favor, mire la siguiente situación:

[email protected]:$ cat test_overflow.c 
#include <stdio.h> 
#include <string.h> 

int check_password(char *password){ 
    int flag = 0; 
    char buffer[20]; 
    strcpy(buffer, password); 

    if(strcmp(buffer, "mypass") == 0){ 
     flag = 1; 
    } 
    if(strcmp(buffer, "yourpass") == 0){ 
     flag = 1; 
    } 
    return flag; 
} 

int main(int argc, char *argv[]){ 
    if(argc >= 2){ 
     if(check_password(argv[1])){ 
      printf("%s", "Access granted\n"); 
     }else{ 
      printf("%s", "Access denied\n"); 
     } 
    }else{ 
     printf("%s", "Please enter password!\n"); 
    } 
} 
[email protected]:$ gcc -g -fno-stack-protector test_overflow.c 
[email protected]:$ ./a.out mypass 
Access granted 
[email protected]:$ ./a.out yourpass 
Access granted 
[email protected]:$ ./a.out wepass 
Access denied 
[email protected]:$ ./a.out wepassssssssssssssssss 
Access granted 

[email protected]:$ gcc -g -fstack-protector test_overflow.c 
[email protected]:$ ./a.out wepass 
Access denied 
[email protected]:$ ./a.out mypass 
Access granted 
[email protected]:$ ./a.out yourpass 
Access granted 
[email protected]:$ ./a.out wepassssssssssssssssss 
*** stack smashing detected ***: ./a.out terminated 
======= Backtrace: ========= 
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xce0ed8] 
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0xce0e90] 
./a.out[0x8048524] 
./a.out[0x8048545] 
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xc16b56] 
./a.out[0x8048411] 
======= Memory map: ======== 
007d9000-007f5000 r-xp 00000000 08:06 5776  /lib/libgcc_s.so.1 
007f5000-007f6000 r--p 0001b000 08:06 5776  /lib/libgcc_s.so.1 
007f6000-007f7000 rw-p 0001c000 08:06 5776  /lib/libgcc_s.so.1 
0090a000-0090b000 r-xp 00000000 00:00 0   [vdso] 
00c00000-00d3e000 r-xp 00000000 08:06 1183  /lib/tls/i686/cmov/libc-2.10.1.so 
00d3e000-00d3f000 ---p 0013e000 08:06 1183  /lib/tls/i686/cmov/libc-2.10.1.so 
00d3f000-00d41000 r--p 0013e000 08:06 1183  /lib/tls/i686/cmov/libc-2.10.1.so 
00d41000-00d42000 rw-p 00140000 08:06 1183  /lib/tls/i686/cmov/libc-2.10.1.so 
00d42000-00d45000 rw-p 00000000 00:00 0 
00e0c000-00e27000 r-xp 00000000 08:06 4213  /lib/ld-2.10.1.so 
00e27000-00e28000 r--p 0001a000 08:06 4213  /lib/ld-2.10.1.so 
00e28000-00e29000 rw-p 0001b000 08:06 4213  /lib/ld-2.10.1.so 
08048000-08049000 r-xp 00000000 08:05 1056811 /dos/hacking/test/a.out 
08049000-0804a000 r--p 00000000 08:05 1056811 /dos/hacking/test/a.out 
0804a000-0804b000 rw-p 00001000 08:05 1056811 /dos/hacking/test/a.out 
08675000-08696000 rw-p 00000000 00:00 0   [heap] 
b76fe000-b76ff000 rw-p 00000000 00:00 0 
b7717000-b7719000 rw-p 00000000 00:00 0 
bfc1c000-bfc31000 rw-p 00000000 00:00 0   [stack] 
Aborted 
[email protected]:$ 

Cuando he deshabilitado el protector de ataques contra la pila no se detectaron errores, lo que debería haber ocurrido cuando he usado "./a.out wepassssssssssssssssss"

Entonces, para responder a su pregunta anterior, se mostró el mensaje "** aplastamiento de pila detectado: xxx" porque su protector de destrucción de pila estaba activo y descubrió que hay un desbordamiento de pila en su programa.

Simplemente averigüe dónde ocurre eso y corríjalo.

+9

hay muchas faltas de ortografía en mi programa – wearetherock

0

Recibí este error mientras usaba malloc() para asignar algo de memoria a una estructura * después de gastar algo para depurar el código, finalmente utilicé la función free() para liberar la memoria asignada y posteriormente el mensaje de error desapareció :)

0

¿Cuáles podrían ser las posibles razones para esto y cómo lo rectifico?

Un escenario sería en el siguiente ejemplo:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void swap (char *a , char *b); 
void revSTR (char *const src); 

int main (void){ 
    char arr[] = "A-B-C-D-E"; 

    revSTR(arr); 
    printf("ARR = %s\n", arr); 
} 

void swap (char *a , char *b){ 
    char tmp = *a; 
    *a = *b; 
    *b = tmp; 
} 

void revSTR (char *const src){ 
    char *start = src; 
    char *end = start + (strlen(src) - 1); 

    while (start < end){ 
     swap(&(*start) , &(*end)); 
     start++; 
     end--; 
    } 
} 

En este programa se puede revertir una cadena o una parte de la cadena si, por ejemplo, la llamada reverse() con algo como esto:

reverse(arr + 2); 

Si decide pasar a la longitud de la matriz de esta manera:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void swap (char *a , char *b); 
void revSTR (char *const src, size_t len); 

int main (void){ 
    char arr[] = "A-B-C-D-E"; 
    size_t len = strlen(arr); 

    revSTR(arr, len); 
    printf("ARR = %s\n", arr); 
} 

void swap (char *a , char *b){ 
    char tmp = *a; 
    *a = *b; 
    *b = tmp; 
} 

void revSTR (char *const src, size_t len){ 
    char *start = src; 
    char *end = start + (len - 1); 

    while (start < end){ 
     swap(&(*start) , &(*end)); 
     start++; 
     end--; 
    } 
} 

Funciona bien también.

Pero al hacer esto:

revSTR(arr + 2, len); 

Usted consigue llegar:

==7125== Command: ./program 
==7125== 
ARR = A- 
*** stack smashing detected ***: ./program terminated 
==7125== 
==7125== Process terminating with default action of signal 6 (SIGABRT) 
==7125== at 0x4E6F428: raise (raise.c:54) 
==7125== by 0x4E71029: abort (abort.c:89) 
==7125== by 0x4EB17E9: __libc_message (libc_fatal.c:175) 
==7125== by 0x4F5311B: __fortify_fail (fortify_fail.c:37) 
==7125== by 0x4F530BF: __stack_chk_fail (stack_chk_fail.c:28) 
==7125== by 0x400637: main (program.c:14) 

Y esto sucede porque en el primer código, la longitud de arr está marcada en el interior de revSTR() lo cual está bien, pero en el segundo código donde se pasa la longitud:

revSTR(arr + 2, len); 

la longitud ahora es más larga que la longitud real que pasa cuando dice arr + 2.

Longitud de strlen (arr + 2)! = strlen (arr).

0

Stack corruptions usualmente causado por desbordamientos de buffer. Puedes defenderte de ellos programando a la defensiva.

Siempre que acceda a una matriz, coloque una afirmación antes de ella para asegurarse de que el acceso no esté fuera de límites. Por ejemplo:

assert(i + 1 < N); 
assert(i < N); 
a[i + 1] = a[i]; 

Esto hace pensar sobre límites de la matriz y también te hace pensar en la adición de pruebas para disparar si es posible. Si algunas de estas afirmaciones pueden fallar durante el uso normal, conviértalas en una if normal.

Cuestiones relacionadas