2009-08-28 1 views
151

Sto eseguendo il mio file a.out. Dopo l'esecuzione del programma viene eseguito per qualche tempo poi esce con il messaggio:Rilevamento frammento rilevato

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

Quali potrebbero essere le possibili ragioni di questo e come posso accoglierle?

+1

Potresti identificare quali parti del tuo codice causano la distruzione dello stack e pubblicarlo? Quindi probabilmente saremo in grado di indicare esattamente perché succede e come correggerlo. –

risposta

225

Lo stack di smashing è in realtà causato da un meccanismo di protezione utilizzato da gcc per rilevare errori di overflow del buffer. Ad esempio nel seguente frammento:

#include <stdio.h> 

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

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

Il compilatore, (in questo caso gcc) aggiunge variabili protezione (chiamati canarini) che hanno valori noti. Una stringa di input di dimensioni superiori a 10 provoca il danneggiamento di questa variabile, con conseguente SIGABRT per terminare il programma.

Per ottenere alcune informazioni, puoi provare a disabilitare questa protezione di gcc utilizzando l'opzione -fno-stack-protector durante la compilazione. In tal caso, si verificherà un errore diverso, molto probabilmente un errore di segmentazione mentre si sta tentando di accedere a una posizione di memoria illegale. Si noti che -fstack-protector deve essere sempre attivato per i build di rilascio in quanto è una funzionalità di sicurezza.

È possibile ottenere alcune informazioni sul punto di overflow eseguendo il programma con un debugger. Valgrind non funziona bene con gli errori relativi allo stack, ma come un debugger può aiutarti a localizzare in modo preciso la posizione e il motivo del crash.

+2

grazie per questa risposta!Ho scoperto che nel mio caso non avevo inizializzato la variabile che stavo cercando di scrivere su –

+3

Valgrind non funziona bene per gli errori relativi allo stack, poiché non è possibile aggiungere zone rosse lì –

+5

Questa risposta è errata e fornisce consigli pericolosi . Prima di tutto, rimuovere la protezione dello stack non è la soluzione giusta: se stai riscontrando un errore di stack, probabilmente hai una seria vulnerabilità di sicurezza nel tuo codice. La risposta corretta è quella di * correggere il codice bacato *. In secondo luogo, come sottolinea GrasGendarme, la raccomandazione di provare Valgrind non sarà efficace. Tipicamente, Valgrind non funziona per rilevare accessi illegali alla memoria ai dati allocati nello stack. –

7

Si potrebbe provare a eseguire il debug del problema utilizzando valgrind:

La distribuzione Valgrind attualmente include sei strumenti di produzione di qualità: un rilevatore di errore di memoria, due rivelatori di errore filo , una cache e ramo- profiler di previsione, un profiler della cache di generazione di grafici delle chiamate , e un profiler dell'heap. Include anche due strumenti sperimentali: a heap/stack/sovraccarico array globale detector e un generatore di blocchi SimPoint . Funziona sulle seguenti piattaforme : X86/Linux, AMD64/Linux, PPC32/Linux, PPC64/Linux, e X86/Darwin (Mac OS X).

+2

Sì, ma Valgrind non funziona bene per gli overflow dei buffer allocati nello stack, che è la situazione indicata da questo messaggio di errore. –

+3

Come potremmo usare quel * rilevatore di sovraccarico dell'array stack *? Puoi elaborare? –

3

Significa che hai scritto alcune variabili sullo stack in modo illegale, molto probabilmente come risultato di un Buffer overflow.

+9

Lo straripamento dello stack è lo stack che distrugge qualcos'altro. Qui è il contrario: qualcosa è andato in frantumi. –

+5

Non proprio. È una parte della pila che si frantuma in un'altra parte. Quindi è davvero un overflow del buffer, non solo nella parte superiore dello stack, ma "solo" in un'altra parte dello stack. –

13

Si prega di guardare la seguente situazione:

[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]:$ 

Quando ho disabilitato il protettore smashing pila sono stati rilevati errori, che dovrebbe essere accaduto quando ho usato "./a.out wepassssssssssssssssss"

Quindi, per rispondere alla tua domanda di cui sopra, è stato visualizzato il messaggio "** stack smashing detected: xxx" perché il tuo stack smashing protector era attivo e ha scoperto che vi è uno stack overflow nel tuo programma.

Basta scoprire dove si verifica e risolverlo.

+9

ci sono molti errori ortografici nel mio programma – wearetherock

0

Ho ricevuto questo errore durante l'utilizzo di malloc() per allocare memoria a una struct * dopo aver speso questo debug del codice, infine ho usato la funzione free() per liberare la memoria allocata e successivamente il messaggio di errore sparito :)

0

Quali potrebbero essere le possibili ragioni per questo e come posso correggerlo?

Uno scenario sarebbe il seguente esempio:

#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--; 
    } 
} 

In questo programma è possibile invertire una stringa o di una parte della stringa se per esempio chiamata reverse() con qualcosa di simile:

reverse(arr + 2); 

Se si decide di passare la lunghezza della matrice in questo modo:

#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--; 
    } 
} 

Funziona bene.

Ma quando si esegue questa operazione:

revSTR(arr + 2, len); 

Si ottiene ottenere:

==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) 

E questo accade perché nel primo codice, la lunghezza del arr viene verificata all'interno di revSTR() che va bene, ma nel secondo codice in cui si passa la lunghezza:

revSTR(arr + 2, len); 

la lunghezza ora è più lunga della lunghezza effettivamente passata quando dici arr + 2.

Lunghezza strlen (arr + 2)! = strlen (arr).

0

Sovrascrive le corruzioni causate dall'overflow del buffer. Puoi difenderti contro di loro programmando in modo difensivo.

Ogni volta che si accede a un array, inserire un asser prima di assicurarsi che l'accesso non sia fuori limite. Per esempio:

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

Questo ti fa pensare a limiti di matrice e anche ti fa pensare di aggiungere test per innescare loro, se possibile. Se alcune di queste affermazioni possono fallire durante il normale utilizzo, trasformarle in un normale if.