#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
static int
return_1(void)
{
return 1;
}
static void
return_1_end(void)
{
}
static int
return_2(void)
{
return 2;
}
static void
return_2_end(void)
{
}
int
main(int argc, char *argv[])
{
void *maprw, *maprx;
int rv;
size_t page = (size_t)sysconf(_SC_PAGESIZE);
// Create the first mapping that has no protections, but intended
// protections only
maprw = mmap(NULL, page,
PROT_MPROTECT(PROT_EXEC|PROT_WRITE|PROT_READ),
MAP_ANON, -1, 0);
if (maprw == MAP_FAILED)
err(EXIT_FAILURE, "mmap failed");
// Create the second mapping for the same physical space, which
// again has no protections.
maprx = mremap(maprw, page, NULL, page, MAP_REMAPDUP);
if (maprx == MAP_FAILED)
err(EXIT_FAILURE, "mremap failed");
// Set the first mapping read/write
if (mprotect(maprw, page, PROT_READ|PROT_WRITE) == -1)
err(EXIT_FAILURE, "mprotect(rw) failed");
// Set the second mapping read/execute
if (mprotect(maprx, page, PROT_READ|PROT_EXEC) == -1)
err(EXIT_FAILURE, "mprotect(rx) failed");
#define XS(a) (size_t)((uintptr_t)(a ## _end) - (uintptr_t)(a))
// Copy and run the first function
memcpy(maprw, return_1, XS(return_1));
__builtin___clear_cache(maprw, (void *)((uintptr_t)maprw + page));
rv = ((int (*)(void))maprx)();
printf("%d\n", rv);
// Copy and run the second function
memcpy(maprw, return_2, XS(return_2));
__builtin___clear_cache(maprw, (void *)((uintptr_t)maprw + page));
rv = ((int (*)(void))maprx)();
printf("%d\n", rv);
return EXIT_SUCCESS;
}