Stapelschlag erkannt

246

Ich führe meine a.out-Datei aus. Nach der Ausführung wird das Programm einige Zeit ausgeführt und dann mit der folgenden Meldung beendet:

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

Was könnten die möglichen Gründe dafür sein und wie kann ich das beheben?

Biswajyoti Das
quelle
2
Könnten Sie vielleicht identifizieren, welche Teile Ihres Codes den Stapel zerschlagen lassen, und ihn veröffentlichen? Dann werden wir wahrscheinlich genau darauf hinweisen können, warum es passiert und wie man es korrigiert.
Bjarke Freund-Hansen
Ich denke, es ist ein Synonym für Überlauffehler. Wenn Sie beispielsweise ein Array mit 5 Elementen initialisieren, wird dieser Fehler angezeigt, wenn Sie versuchen, das 6. Element oder ein Element außerhalb der Grenzen des Arrays zu schreiben.
DorinPopescu

Antworten:

349

Stack Smashing wird hier tatsächlich durch einen Schutzmechanismus verursacht, der von gcc verwendet wird, um Pufferüberlauffehler zu erkennen. Zum Beispiel im folgenden Snippet:

#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 Schutzvariablen (Canaries genannt) mit bekannten Werten hinzu. Eine Eingabezeichenfolge mit einer Größe größer als 10 führt zu einer 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 mithilfe der Option -fno-stack-protector beim Kompilieren zu deaktivieren . In diesem Fall wird ein anderer Fehler angezeigt, höchstwahrscheinlich ein Segmentierungsfehler, wenn Sie versuchen, auf einen unzulässigen Speicherort zuzugreifen. Beachten Sie, dass -fstack-protectordies für Release-Builds immer aktiviert sein sollte, da es sich um eine Sicherheitsfunktion handelt.

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

sud03r
quelle
3
Danke für diese Antwort! Ich stellte fest, dass ich in meinem Fall die Variable, in die ich schreiben wollte, nicht initialisiert hatte
Ted Pennings
5
Valgrind funktioniert nicht gut für
stapelbezogene
7
Diese Antwort ist falsch und gibt gefährliche Ratschläge. Erstens ist das Entfernen des Stapelschutzes nicht die richtige Lösung. Wenn Sie einen Fehler beim Stapeln von Stapeln erhalten, liegt wahrscheinlich eine schwerwiegende Sicherheitslücke in Ihrem Code vor. Die richtige Antwort ist, den fehlerhaften Code zu beheben . Zweitens, wie grasGendarme betont, wird die Empfehlung, Valgrind auszuprobieren, nicht wirksam sein. Valgrind funktioniert normalerweise nicht zum Erkennen illegaler Speicherzugriffe auf vom Stapel zugewiesene Daten.
DW
22
Das OP fragt nach möglichen Gründen für dieses Verhalten. Meine Antwort liefert ein Beispiel und wie es sich auf einen vernünftigerweise bekannten Fehler bezieht. Außerdem ist das Entfernen des Stapelschutzes keine Lösung, sondern eine Art Experiment, mit dem man mehr Einblicke in das Problem gewinnen kann. Der Rat ist eigentlich, den Fehler irgendwie zu beheben, danke für den Hinweis auf Valgrind, ich werde meine Antwort bearbeiten, um dies widerzuspiegeln.
Sud03r
4
@DW Der Stack-Schutz sollte in einer Release-Version deaktiviert sein, da zunächst die Meldung " Stack Smashing Detected" nur für Entwickler hilfreich ist. zweitens - eine Bewerbung könnte noch Überlebenschancen haben; und drittens - das ist eine winzige Optimierung.
Hi-Angel
33

Beispiel für minimale Reproduktion mit Demontageanalyse

Haupt c

void myfunc(char *const src, int len) {
    int i;
    for (i = 0; i < len; ++i) {
        src[i] = 42;
    }
}

int main(void) {
    char arr[] = {'a', 'b', 'c', 'd'};
    int len = sizeof(arr);
    myfunc(arr, len + 1);
    return 0;
}

GitHub stromaufwärts .

Kompilieren und ausführen:

gcc -fstack-protector -g -O0 -std=c99 main.c
ulimit -c unlimited && rm -f core
./a.out

schlägt wie gewünscht fehl:

*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

Getestet unter Ubuntu 16.04, GCC 6.4.0.

Demontage

Nun schauen wir uns die Demontage an:

objdump -D a.out

was beinhaltet:

int main (void){
  400579:       55                      push   %rbp
  40057a:       48 89 e5                mov    %rsp,%rbp

  # Allocate 0x10 of stack space.
  40057d:       48 83 ec 10             sub    $0x10,%rsp

  # Put the 8 byte canary from %fs:0x28 to -0x8(%rbp),
  # which is right at the bottom of the stack.
  400581:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400588:       00 00 
  40058a:       48 89 45 f8             mov    %rax,-0x8(%rbp)

  40058e:       31 c0                   xor    %eax,%eax
    char arr[] = {'a', 'b', 'c', 'd'};
  400590:       c6 45 f4 61             movb   $0x61,-0xc(%rbp)
  400594:       c6 45 f5 62             movb   $0x62,-0xb(%rbp)
  400598:       c6 45 f6 63             movb   $0x63,-0xa(%rbp)
  40059c:       c6 45 f7 64             movb   $0x64,-0x9(%rbp)
    int len = sizeof(arr);
  4005a0:       c7 45 f0 04 00 00 00    movl   $0x4,-0x10(%rbp)
    myfunc(arr, len + 1);
  4005a7:       8b 45 f0                mov    -0x10(%rbp),%eax
  4005aa:       8d 50 01                lea    0x1(%rax),%edx
  4005ad:       48 8d 45 f4             lea    -0xc(%rbp),%rax
  4005b1:       89 d6                   mov    %edx,%esi
  4005b3:       48 89 c7                mov    %rax,%rdi
  4005b6:       e8 8b ff ff ff          callq  400546 <myfunc>
    return 0;
  4005bb:       b8 00 00 00 00          mov    $0x0,%eax
}
  # Check that the canary at -0x8(%rbp) hasn't changed after calling myfunc.
  # If it has, jump to the failure point __stack_chk_fail.
  4005c0:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
  4005c4:       64 48 33 0c 25 28 00    xor    %fs:0x28,%rcx
  4005cb:       00 00 
  4005cd:       74 05                   je     4005d4 <main+0x5b>
  4005cf:       e8 4c fe ff ff          callq  400420 <__stack_chk_fail@plt>

  # Otherwise, exit normally.
  4005d4:       c9                      leaveq 
  4005d5:       c3                      retq   
  4005d6:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4005dd:       00 00 00 

Beachten Sie die handlichen Kommentare automatisch hinzugefügt von objdump‚s Modul künstlicher Intelligenz .

Wenn Sie dieses Programm mehrmals über GDB ausführen, sehen Sie Folgendes:

  • Der Kanarienvogel erhält jedes Mal einen anderen Zufallswert
  • Die letzte Schleife von myfuncist genau das, was die Adresse des Kanarienvogels ändert

Der Kanarienvogel wird randomisiert, indem er mit gesetzt %fs:0x28wird. Dieser enthält einen zufälligen Wert, wie unter:

Debug-Versuche

Von nun an ändern wir den Code:

    myfunc(arr, len + 1);

stattdessen sein:

    myfunc(arr, len);
    myfunc(arr, len + 1); /* line 12 */
    myfunc(arr, len);

interessanter sein.

Wir werden dann versuchen zu sehen, ob wir den Täteraufruf + 1mit einer Methode lokalisieren können, die automatisierter ist als nur das Lesen und Verstehen des gesamten Quellcodes.

gcc -fsanitize=address um den Address Sanitizer (ASan) von Google zu aktivieren

Wenn Sie mit diesem Flag neu kompilieren und das Programm ausführen, wird Folgendes ausgegeben:

#0 0x4008bf in myfunc /home/ciro/test/main.c:4
#1 0x40099b in main /home/ciro/test/main.c:12
#2 0x7fcd2e13d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400798 in _start (/home/ciro/test/a.out+0x40079

gefolgt von etwas mehr farbiger Ausgabe.

Dies zeigt deutlich die problematische Linie 12.

Der Quellcode hierfür lautet: https://github.com/google/sanitizers, aber wie wir aus dem Beispiel gesehen haben, wird er bereits in GCC übertragen.

ASan kann auch andere Speicherprobleme wie Speicherverluste erkennen: Wie finde ich einen Speicherverlust in einem C ++ - Code / Projekt?

Valgrind SGCheck

Wie von anderen erwähnt , ist Valgrind nicht gut darin, diese Art von Problem zu lösen.

Es gibt ein experimentelles Tool namens SGCheck :

SGCheck ist ein Tool zum Auffinden von Überläufen von Stack- und globalen Arrays. Es funktioniert mit einem heuristischen Ansatz, der aus einer Beobachtung der wahrscheinlichen Formen von Stapel- und globalen Array-Zugriffen abgeleitet wurde.

Ich war also nicht sehr überrascht, als der Fehler nicht gefunden wurde:

valgrind --tool=exp-sgcheck ./a.out

Die Fehlermeldung sollte anscheinend so aussehen: Valgrind fehlender Fehler

GDB

Eine wichtige Beobachtung ist, dass, wenn Sie das Programm über GDB ausführen oder die coreDatei nachträglich untersuchen :

gdb -nh -q a.out core

Dann sollte GDB, wie wir auf der Baugruppe gesehen haben, Sie auf das Ende der Funktion hinweisen, die die Kanarienvogelprüfung durchgeführt hat:

(gdb) bt
#0  0x00007f0f66e20428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007f0f66e2202a in __GI_abort () at abort.c:89
#2  0x00007f0f66e627ea in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f0f66f7a49f "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f0f66f0415c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f0f66f7a481 "stack smashing detected") at fortify_fail.c:37
#4  0x00007f0f66f04100 in __stack_chk_fail () at stack_chk_fail.c:28
#5  0x00000000004005f6 in main () at main.c:15
(gdb) f 5
#5  0x00000000004005f6 in main () at main.c:15
15      }
(gdb)

Und deshalb ist das Problem wahrscheinlich bei einem der Aufrufe dieser Funktion.

Als nächstes versuchen wir, den genauen fehlgeschlagenen Anruf zu lokalisieren, indem wir den ersten einzelnen Schritt unmittelbar nach dem Setzen des Kanarienvogels ausführen:

  400581:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400588:       00 00 
  40058a:       48 89 45 f8             mov    %rax,-0x8(%rbp)

und die Adresse beobachten:

(gdb) p $rbp - 0x8
$1 = (void *) 0x7fffffffcf18
(gdb) watch 0x7fffffffcf18
Hardware watchpoint 2: *0x7fffffffcf18
(gdb) c
Continuing.

Hardware watchpoint 2: *0x7fffffffcf18

Old value = 1800814336
New value = 1800814378
myfunc (src=0x7fffffffcf14 "*****?Vk\266", <incomplete sequence \355\216>, len=5) at main.c:3
3           for (i = 0; i < len; ++i) {
(gdb) p len
$2 = 5
(gdb) p i
$3 = 4
(gdb) bt
#0  myfunc (src=0x7fffffffcf14 "*****?Vk\266", <incomplete sequence \355\216>, len=5) at main.c:3
#1  0x00000000004005cc in main () at main.c:12

Dies lässt uns nun bei der richtigen beleidigenden Anweisung zurück: len = 5und i = 4hat uns in diesem speziellen Fall auf die Täterlinie 12 hingewiesen.

Die Rückverfolgung ist jedoch beschädigt und enthält Müll. Eine korrekte Rückverfolgung würde folgendermaßen aussehen:

#0  myfunc (src=0x7fffffffcf14 "abcd", len=4) at main.c:3
#1  0x00000000004005b8 in main () at main.c:11

Vielleicht könnte dies den Stapel beschädigen und Sie daran hindern, die Ablaufverfolgung zu sehen.

Bei dieser Methode muss auch bekannt sein, was der letzte Aufruf der Kanarienvogelprüffunktion ist. Andernfalls treten falsch positive Ergebnisse auf, die nur dann möglich sind, wenn Sie das Reverse-Debugging verwenden .

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
16

Bitte schauen Sie sich die folgende Situation an:

ab@cd-x:$ 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");
    }
}
ab@cd-x:$ gcc -g -fno-stack-protector test_overflow.c 
ab@cd-x:$ ./a.out mypass
Access granted
ab@cd-x:$ ./a.out yourpass
Access granted
ab@cd-x:$ ./a.out wepass
Access denied
ab@cd-x:$ ./a.out wepassssssssssssssssss
Access granted

ab@cd-x:$ gcc -g -fstack-protector test_overflow.c 
ab@cd-x:$ ./a.out wepass
Access denied
ab@cd-x:$ ./a.out mypass
Access granted
ab@cd-x:$ ./a.out yourpass
Access granted
ab@cd-x:$ ./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
ab@cd-x:$ 

Als ich den Stack Smashing Protector deaktivierte, wurden keine Fehler festgestellt. Dies hätte passieren müssen, wenn ich "./a.out wepassssssssssssssssss" verwendet habe.

Um Ihre Frage oben zu beantworten, wurde die Meldung "** Stapelzerstörung erkannt: xxx" angezeigt, da Ihr Stapelzerstörungsschutz aktiv war und festgestellt wurde, dass in Ihrem Programm ein Stapelüberlauf vorliegt.

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

Wearetherock
quelle
7

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

Die Valgrind-Distribution enthält derzeit sechs Tools in Produktionsqualität: einen Speicherfehlerdetektor, zwei Thread-Fehlerdetektoren, einen Cache- und Verzweigungsvorhersage-Profiler, einen Cache-Profiler zur Erzeugung von Aufrufgraphen und einen Heap-Profiler. Es enthält außerdem zwei experimentelle Tools: einen Heap / Stack / Global Array Overrun-Detektor und einen SimPoint-Basisblockvektorgenerator. Es läuft auf den folgenden Plattformen: X86 / Linux, AMD64 / Linux, PPC32 / Linux, PPC64 / Linux und X86 / Darwin (Mac OS X).

hlovdal
quelle
2
Ja, aber Valgrind funktioniert nicht gut bei Überläufen von stapelzugewiesenen Puffern. Dies ist die Situation, auf die diese Fehlermeldung hinweist.
DW
4
Wie könnten wir diesen Stack-Array-Überlaufdetektor verwenden ? Können Sie das näher erläutern?
Craig McQueen
@CraigMcQueen Ich habe versucht, Valgrinds experimentellen heuristischen SGCheck-Stack-Smashing-Detektor an einem minimalen Beispiel zu verwenden: stackoverflow.com/a/51897264/895245, aber es ist fehlgeschlagen.
Ciro Santilli 法轮功 冠状 病 六四 事件 17
4

Dies bedeutet, dass Sie auf illegale Weise auf einige Variablen auf dem Stapel geschrieben haben, höchstwahrscheinlich als Ergebnis eines Pufferüberlaufs .

Sternenblau
quelle
9
Stapelüberlauf ist der Stapel, der in etwas anderes zerschmettert. Hier ist es umgekehrt: Etwas ist in den Stapel eingeschlagen.
Peter Mortensen
5
Nicht wirklich. Es ist ein Teil des Stapels, der in einen anderen Teil zerschmettert. Es ist also wirklich ein Pufferüberlauf, nur nicht über dem Stapel, sondern "nur" in einen anderen Teil des Stapels.
Bas Wijnen
2

Was könnten die möglichen Gründe dafür sein und wie kann ich das beheben?

Ein Szenario wäre das folgende Beispiel:

#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 des Strings umkehren, wenn Sie beispielsweise Folgendes aufrufen reverse():

reverse( arr + 2 );

Wenn Sie die Länge des Arrays wie folgt übergeben möchten:

#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:

==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 im ersten Code die Länge von arrüberprüft revSTR()wird, was in Ordnung ist, aber im 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 sagen arr + 2.

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

Michi
quelle
1
Ich mag dieses Beispiel, weil es nicht auf Standardbibliotheksfunktionen wie getsund basiert scrcpy. Ich frage mich, ob wir weiter minimieren könnten. Ich würde zumindest loswerden string.hmit size_t len = sizeof( arr );. Getestet auf gcc 6.4, Ubuntu 16.04. Ich würde auch das fehlerhafte Beispiel mit dem geben, arr + 2um das Einfügen von Kopien zu minimieren.
Ciro Santilli 法轮功 冠状 病 六四 事件 17
1

Stapelverfälschungen, 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, stellen Sie ihm eine Zusicherung vor, um sicherzustellen, dass der Zugriff nicht außerhalb der Grenzen liegt. Beispielsweise:

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

Dies lässt Sie über Array-Grenzen nachdenken und über das Hinzufügen von Tests, um diese nach Möglichkeit auszulösen. Wenn einige dieser Behauptungen während des normalen Gebrauchs fehlschlagen können, verwandeln Sie sie in eine reguläre if.

Calmarius
quelle
0

Ich habe diesen Fehler erhalten, als ich malloc () verwendet habe, um einer Struktur * Speicher zuzuweisen. Nachdem ich einige Zeit damit verbracht hatte, den Code zu debuggen, habe ich schließlich die Funktion free () verwendet, um den zugewiesenen Speicher freizugeben, und anschließend ist die Fehlermeldung verschwunden :)

Djangodude
quelle
0

Eine andere Quelle für das Zerschlagen von Stapeln ist die (falsche) Verwendung von vfork()anstelle von fork().

Ich habe gerade einen Fall debuggt, in dem der untergeordnete Prozess execve()die ausführbare Zieldatei nicht erreichen konnte und einen Fehlercode zurückgegeben hat, anstatt aufzurufen _exit().

Da vfork()dieses Kind erzeugt wurde, kehrte es zurück, während es tatsächlich noch im Prozessbereich des Elternteils ausgeführt wurde, wodurch nicht nur der Stapel des Elternteils beschädigt wurde, sondern auch zwei unterschiedliche Diagnosesätze durch "nachgeschalteten" Code gedruckt wurden.

Ändern vfork() auf fork()behebt beide Probleme, ebenso wie das Ändern der returnAussage des Kindes in _exit()stattdessen.

Da execve()der untergeordnete Code dem Aufruf jedoch Aufrufe anderer Routinen vorausgeht (in diesem speziellen Fall zum Festlegen der UID / GID), erfüllt er technisch nicht die Anforderungen für vfork(), sodass eine Änderung der Verwendung fork()hier richtig ist.

(Beachten Sie, dass das problematisch ist return Anweisung war nicht wirklich als solche codiert - stattdessen ein Makro aufgerufen wurde, und das Makro entschieden , ob auf _exit()oder returnbasierend auf einer globalen Variablen , damit es nicht sofort klar war , dass das Kind Code für nicht - konforme wurde. vfork()Nutzung. )

Weitere Informationen finden Sie unter:

Der Unterschied zwischen fork (), vfork (), exec () und clone ()

James Craig Burley
quelle