The code must be in a page with execute permission. By default, stack and read-write static data (like non-const globals) are in pages mapped without exec permission, for security reasons.
The simplest way is to compile with gcc -z execstack
, which links your program such that stack and global variables (static storage) get mapped in executable pages, and so do allocations with malloc
.
Another way to do it without making everything executable is to copy this binary machine code into an executable buffer.
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48,
0x89,0x75,0xf0,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3,0x00};
/*
00000000004004b4 <main> 55 push %rbp
00000000004004b5 <main+0x1> 48 89 e5 mov %rsp,%rbp
00000000004004b8 <main+0x4> 89 7d fc mov %edi,-0x4(%rbp)
00000000004004bb <main+0x7> 48 89 75 f0 mov %rsi,-0x10(%rbp)
'return 42;'
00000000004004bf <main+0xb> b8 2a 00 00 00 mov $0x2a,%eax
'}'
00000000004004c4 <main+0x10> c9 leaveq
00000000004004c5 <main+0x11> c3 retq
*/
int main(int argc, char **argv) {
void *buf;
/* copy code to executable buffer */
buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANON,-1,0);
memcpy (buf, code, sizeof(code));
__builtin___clear_cache(buf, buf+sizeof(code)-1); // on x86 this just stops memcpy from optimizing away as a dead store
/* run code */
int i = ((int (*) (void))buf)();
printf("get this done. returned: %d", i);
return 0;
}
output:
get this done. returned: 42
RUN SUCCESSFUL (total time: 57ms)
Without __builtin___clear_cache
, this could break with optimization enabled because gcc would think the memcpy
was a dead store and optimize it away. When compiling for x86, __builtin___clear_cache
does not actually clear any cache; there are zero extra instructions; it just marks the memory as "used" so stores to it aren't considered "dead". (See the gcc manual.)
Another option would be to mprotect
the page containing the char code[]
array, giving it PROT_READ|PROT_WRITE|PROT_EXEC
. This works whether it's a local array (on the stack) or global in the .data
.
Or if it's const char code[]
in the .rodata
section, you might just give it PROT_READ|PROT_EXEC
.
(In versions of binutils ld
from before about 2019, the .rodata
got linked as part of the same segment as .text
, and was already mapped executable. But recent ld
gives it a separate segment so it can be mapped without exec permission so const char code[]
doesn't give you an executable array anymore, but it used to so you may this old advice in other places.)