There is something that puzzles me about the behaviour of the following code (SMP Debian 4.19.260-1 (2022-09-29) x86_64 GNU/Linux):
#include <stdio.h>
const char
shellcode[]="\xb8\×01\×00\x00\x00\×48\xbe\×48\×65\×6c\x6c\×6f\×00\×00\×00\×56\×48\x89\xe6\xba\x05\x00\x00\x00\x0f\x05\xb8\x3c\x00\x00\x00\x0f\x05";
int main(){
(*(void (*) ()) shellcode)();
return 0;
}
When I execute the program by the debugger I see that the code executed after the cast of the array to a function is located where one expects to see it, that is, in the initialized globals area (since it is defined as such). In other words the code is very low in the process address space and definitely not on the stack.
Nevertheless, to actually run the code without receiving a SIGSEGV, one must compile it with the executable stack option -z execstack. How come this happens if the code is NOT on the stack?
Update:
I used these commands:
$ gcc testshellcode.c -o testshellcode
$ ./testshellcode
Segmentation fault
$ gcc -z execstack testshellcode.c -o testshellcode
$ ./testshellcode
Hello
I am using gcc (Debian 8.3.0-6) 8.3.0
.
Solution found: The execstack flag makes all the pages in memory executable, not just those of the stack. See:
Why is execstack required to execute code on the heap?
Exactly what cases does the gcc execstack flag allow and how does it enforce it?