如何将C程序子进程返回码映射为对应错误名称(如-11对应段错误)
Great question! When your fuzzer spawns a child process that crashes (like with a segmentation fault), the "return value" you're seeing (-11 in your case) isn't a direct exit code—it's actually a misinterpretation of the child's termination status. Here's how to properly map these values to human-readable error names:
1. Understand the Child Termination Status on Unix-like Systems
When a process crashes due to a signal (like SIGSEGV for segmentation faults), the OS doesn't let it exit normally. Instead, the kernel sends a signal to terminate it, and the parent process (your fuzzer) can retrieve this signal info using waitpid() or wait().
The status value returned by these functions is a composite integer that encodes two key pieces of information:
- Whether the process exited normally or was killed by a signal
- If killed by a signal, which specific signal was responsible
You need to use POSIX-standard macros to unpack this status correctly:
WIFSIGNALED(status): Returns true if the process was terminated by a signalWTERMSIG(status): IfWIFSIGNALEDis true, this gives you the signal number that killed the processWIFEXITED(status): Returns true if the process exited normally (e.g., viaexit())WEXITSTATUS(status): IfWIFEXITEDis true, this gives the process's exit code
Your -11 is likely a result of reading the raw status value as a signed integer instead of unpacking it properly. For SIGSEGV (signal number 11), the raw status might be represented as -11 in some contexts, but that's not the right way to interpret it.
2. Map Signal Numbers to Human-Readable Names
Once you have the correct signal number (e.g., 11 for SIGSEGV), you have two reliable ways to get its name/description:
Option 1: Use the strsignal() Function (Simplest & Recommended)
This POSIX-standard function takes a signal number and returns a human-readable string describing the signal. For example:
strsignal(SIGSEGV)returns"Segmentation fault"strsignal(SIGABRT)returns"Aborted"
Here's a code snippet showing how to integrate this into your fuzzer:
#include <sys/wait.h> #include <string.h> #include <stdio.h> #include <signal.h> void process_child_exit(int status) { if (WIFSIGNALED(status)) { int sig_num = WTERMSIG(status); printf("Crash detected: %s (signal %d)\n", strsignal(sig_num), sig_num); // For your test case, this would print: "Crash detected: Segmentation fault (signal 11)" } else if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); printf("Process exited normally with code %d\n", exit_code); } } // Example usage in your fuzzer: // pid_t child_pid = fork(); // if (child_pid == 0) { /* Execute your target vulnerable C program */ } // else { // int status; // waitpid(child_pid, &status, 0); // process_child_exit(status); // }
Option 2: Manual Signal Mapping Table
If you need more control over the output strings (or for rare systems where strsignal() isn't available), you can create your own mapping:
#include <signal.h> const char* get_signal_name(int sig_num) { switch(sig_num) { case SIGSEGV: return "Segmentation Fault"; case SIGABRT: return "Aborted"; case SIGILL: return "Illegal Instruction"; case SIGFPE: return "Floating Point Exception"; case SIGBUS: return "Bus Error"; // Add more signals as needed for your testing default: return "Unknown Crash Signal"; } }
3. Verify with Your Test Case
In your example, when you ran the payload that triggered a segmentation fault, the child process was killed by signal 11 (SIGSEGV). Using the methods above, your fuzzer will correctly map this to "Segmentation Fault" instead of showing the raw -11 value.
内容的提问来源于stack exchange,提问作者0x2E5

