Linux: executing code loaded into memory manually

I am experimenting with function pointers on Linux and trying to run this program in C:

#include <stdio.h> #include <string.h> int myfun() { return 42; } int main() { char data[500]; memcpy(data, myfun, sizeof(data)); int (*fun_pointer)() = (void*)data; printf("%d\n", fun_pointer()); return 0; } 

Unfortunately, it does not answer the call to fun_pointer() . I suspect it is associated with some memory flags, but I did not find information about this.

Could you explain why this code is segfaults? I do not see the fixed size of the data array, this is normal and copying without calling the function is successful.

UPD Finally, I found that the memory segment should be marked as executable with mprotect called with the PROT_EXEC flag. In addition, the memory segment must be returned by the mmap function, as specified in the POSIX specification. There is the same code that uses allocated mmap memory with the PROT_EXEC flag (and works):

 #include <stdio.h> #include <string.h> #include <sys/mman.h> int myfun() { return 42; } int main() { size_t size = (char*)main - (char*)myfun; char *data = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); memcpy(data, myfun, size); int (*fun_pointer)() = (void*)data; printf("%d\n", fun_pointer()); munmap(data, size); return 0; } 

This example should be run with the -fPIC gcc option to ensure that the code in the functions is position-independent.

+5
source share
3 answers

There are several problems:

+5
source

In addition to the Diask answer, you probably want to use some JIT compilation (to generate executable code in memory), and you must be sure that the memory area containing the code is executable (see mprotect (2) and NX bit , often call stacks are not executed for security reasons). You can use GNU lightning (fast emitting slow machine code), asmjit , libjit , LLVM , GCCJIT (capable of slowly generating fast optimized machine code). You can also emit some C code in some temporary file /tmp/emittedcode.c , fork the compilation command gcc -Wall -O -fPIC -shared /tmp/emittedcode.c -o /tmp/emittedcode.so , then dlopen (3) that the common object is /tmp/emittedcode.so and use dlsym (3) to find function pointers by their name.

See also this , this , this , this and which correspond. Read about trampoline code , closing and continuing and CPS .

Of course, copying code from one zone to another usually does not work (it must be the position of independent code to make this work, or you need your own relocation mechanism, a bit like linker ).

+2
source

This is because this line is incorrect:

memcpy(data, myfun, sizeof(data));

You copy the code (compiled) of the function instead of the address of the function.

myfun and myfun will have the same address, so to perform the memcpy operation, you will need to use a pointer to the function and then copy it to the address.

Example:

 int (*p)(); p = myfun; memcpy(data, &p, sizeof(data)); 
0
source

Source: https://habr.com/ru/post/1239330/


All Articles