I'd like to copy and call a function, but the code below segfaults when calling the buffer. What do I have to change? (Linux, x86)
#include <string.h>
#include <malloc.h>
#include <stdio.h>
int foo () { return 12; }
void foo_end () {}
int main () {
int s = (unsigned long long) foo_end - (unsigned long long) foo;
int (*f) () = (int (*)()) malloc (s);
memcpy ((void*) f, (const void*) foo, s);
printf ("%d %d\n", f (), foo ());
}
EDIT: Working solution:
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
int foo () { return 12; }
void foo_end () {}
int main () {
int s = (unsigned long long) foo_end - (unsigned long long) foo;
int (*f) () = (int (*)()) malloc (s);
memcpy ((void*) f, (const void*) foo, s);
long ps = sysconf (_SC_PAGESIZE);
void *fp = (void*) ((unsigned long long) f & ~((unsigned long long) (ps-1)));
if (mprotect ((void*) fp, ps, PROT_READ | PROT_WRITE | PROT_EXEC)) return -1;
printf ("%d %d\n", f (), foo ());
}
Potentially you're using an OS which does not grant execute permission to data segments.
Some environments will protect data pages against execution, to avoid various types of security problems (or exploits for them).
Consider calling mprotect() to enable execute for that page and report what happens.
Whoa, that code has so many issues.
- You can't know that the functions are laid out sequentially in memory, with no padding
between them
- You can't know that the pointers to two functions are subtractable
- You can't know that memory returned by
malloc()
can be called into
In short, don't do this.
Update:
In Linux, I think you can use mprotect()
to set the permissions on a block of memory. I thought this needed root, but apparently not (as long as you're in your own process' memory).
This is a common issue among embedded systems folk. This technique is often times used for copying from Read-Only Memory into Random-Access Memory (write and read capable). There is no elegant nor standard solution using standard C or C++.
A simpler solution is to use the Linker to define some new, non-standard, segments. Use non-standard #pragma
to instruct the compiler to place the function into a new segment. Use non-standard compiler directive to access the beginning address and ending address of this segment. This will allow you to get the size of the function.
A safer method for the destination is to create another segment with executable and write attributes. Copy the data in the function segment into this executable segment. Set up a function pointer to point to the start of this segment. Execute the function via the pointer.
Another solution is to perform this in assembly language. Often, assemblers give you more freedom (to shoot your foot) to manipulate memory like this in a lower level.
Also, review your operating system loader, memory attributes and protection schemes. Some OSes may restrict this kind of behavior to Kernel privilege or higher.