2009-08-28 6 views
151

Ich führe meine a.out Datei aus. Nach der Ausführung wird das Programm für einige Zeit dann mit der Meldung beendet:Stack Smashing erkannt

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

Was die möglichen Gründe dafür sein könnte, und wie kann ich es beheben?

+1

Könntest du vielleicht herausfinden, welche Teile deines Codes den Stapel zerstören und ihn veröffentlichen? Dann werden wir wahrscheinlich genau feststellen können, warum es passiert und wie wir es korrigieren können. –

Antwort

225

Stack Smashing wird hier aufgrund eines Schutzmechanismus verursacht, der von gcc verwendet wird, um Pufferüberlauffehler zu erkennen. Zum Beispiel im folgenden Ausschnitt:

#include <stdio.h> 

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

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

Der Compiler, (in diesem Fall gcc) fügt Schutz Variablen (genannt Kanarienvögel), die bekannten Werte haben. Eine Eingabezeichenfolge mit einer Größe größer als 10 verursacht eine Beschädigung dieser Variablen, was dazu führt, dass SIGABRT das Programm beendet.

Um einen Einblick zu erhalten, können Sie versuchen, diesen Schutz von gcc mit der Option -fno-stack-protector während des Kompilierens zu deaktivieren. In diesem Fall erhalten Sie einen anderen Fehler, höchstwahrscheinlich einen Segmentierungsfehler, wenn Sie versuchen, auf einen ungültigen Speicherort zuzugreifen. Beachten Sie, dass -fstack-protector immer für Release-Builds aktiviert sein sollte, da es sich um eine Sicherheitsfunktion handelt.

Sie können Informationen über den Überlaufpunkt erhalten, indem Sie das Programm mit einem Debugger ausführen. Valgrind funktioniert nicht gut mit Stack-bezogenen Fehlern, aber wie ein Debugger kann es Ihnen helfen, den Ort und den Grund für den Absturz zu lokalisieren.

+2

danke für diese Antwort!Ich fand, dass in meinem Fall ich die Variable nicht initialisiert hatte, die ich versuchte zu schreiben –

+3

Valgrind funktioniert nicht gut für stack-related Fehler, da es rote Zonen dort nicht hinzufügen kann –

+5

Diese Antwort ist falsch und bietet gefährliche Ratschläge . Zunächst einmal ist es nicht die richtige Lösung, den Stack Protector zu entfernen. Wenn Sie einen Stack-Smashing-Fehler erhalten, haben Sie wahrscheinlich eine ernsthafte Sicherheitslücke in Ihrem Code. Die richtige Antwort ist * den fehlerhaften Code * zu beheben. Zweitens, wie grasGandmee betont, wird die Empfehlung, Valgrind zu testen, nicht effektiv sein. Valgrind funktioniert normalerweise nicht zum Erkennen illegaler Speicherzugriffe auf Daten, die dem Stack zugewiesen sind. –

7

Sie könnten versuchen, das Problem zu debuggen mit valgrind:

Die Valgrind Verteilung derzeit umfasst sechs Produktionsqualität Tools: ein Speicherfehlerdetektor, zwei Faden Fehlerdetektoren, einen Cache und branchen- Prädiktions-Profiler, ein Call-Graph, der Cache-Profiler, und einen Heap-Profiler generiert. Es enthält auch zwei experimentelle Werkzeuge: ein Heap/Stack/globale Array Überlauf Detektor, und ein SimPoint Basisblock Vektorgenerator. Es läuft auf der folgenden Plattformen: X86/Linux, AMD64/Linux, PPC32/Linux, PPC64/Linux, und X86/Darwin (Mac OS X).

+2

Ja, aber Valgrind funktioniert nicht gut für Überläufe von Stack-allokierten Puffern, was die Situation ist, die diese Fehlermeldung anzeigt. –

+3

Wie könnten wir diesen * Stack Array Overrun Detector * verwenden? Kannst du es ausarbeiten? –

3

Es bedeutet, dass Sie auf eine ungültige Weise auf einige Variablen auf dem Stapel geschrieben haben, wahrscheinlich als Ergebnis einer Buffer overflow.

+9

Stapelüberlauf ist der Stapel, der in etwas anderes zertrümmert. Hier ist es umgekehrt: Etwas ist in den Stapel eingebrochen. –

+5

Nicht wirklich. Es ist ein Teil des Stapels, der in einen anderen Teil eindringt. Es ist also wirklich ein Pufferüberlauf, nur nicht über den Stapel, sondern "nur" in einen anderen Teil des Stapels. –

13

Bitte schauen Sie auf die folgende Situation:

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

Wenn ich den Stapel Zerschlagung Schutz deaktiviert keine Fehler festgestellt wurden, die geschehen sollte, wenn ich gebraucht „./a.out wepassssssssssssssssss“

Um deine Frage zu beantworten, wurde die Nachricht "** Stack Smashing Detected: xxx" angezeigt, weil dein Stack-Zerschlagungsschutz aktiv war und in deinem Programm ein Stack-Überlauf festgestellt wurde.

Finden Sie einfach heraus, wo das auftritt, und beheben Sie es.

+9

In meinem Programm sind viele Rechtschreibfehler – wearetherock

0

Ich habe diesen Fehler bei der Verwendung von malloc(), um etwas Speicher zu einer Struktur * nach einigen Ausgaben dieses Debuggen des Codes zuzuteilen, habe ich endlich free() -Funktion verwendet, um den zugewiesenen Speicher freizugeben und anschließend die Fehlermeldung weg :)

0

Was könnten die möglichen Gründe dafür sein und wie behebe ich es?

Ein Szenario, in dem folgenden Beispiel wäre:

#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 diesem Programm können Sie einen String oder einen Teil der Zeichenfolge umkehren können, wenn Sie zum Beispiel Anruf reverse() mit etwas wie folgt aus:

reverse(arr + 2); 

Wenn Sie sich entscheiden, die Länge des Array wie folgt weitergeben müssen:

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

Funktioniert auch gut.

Aber wenn Sie dies tun:

revSTR(arr + 2, len); 

Sie erhalten erhalten:

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

Und dies geschieht, weil in dem ersten Code, die Länge von arr innerhalb von revSTR() geprüft, was in Ordnung ist, aber in dem zweiten Code, in dem Sie die Länge übergeben:

revSTR(arr + 2, len); 
Die Länge ist jetzt länger als die tatsächliche Länge, die Sie überschreiten, wenn Sie arr + 2 sagen.

Länge von strlen (arr + 2)! = strlen (arr).

0

Stapelfehler, die normalerweise durch Pufferüberläufe verursacht werden. Sie können sich gegen sie verteidigen, indem Sie defensiv programmieren.

Wenn Sie auf ein Array zugreifen, legen Sie eine Assert davor, um sicherzustellen, dass der Zugriff nicht außerhalb der Grenzen ist. Zum Beispiel:

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

Dies macht denken Sie über Feldgrenzen und macht auch denken Sie über Tests Hinzufügen von ihnen, wenn möglich auszulösen. Wenn einige dieser Behauptungen bei normalem Gebrauch versagen, sollten Sie sie zu einem normalen if machen.