[cfarm-users] make pages writable and executable

Bruno Haible bruno at clisp.org
Mon Mar 22 10:11:31 CET 2021

Christian Jullien wrote:
> Again, we'll have to probably adapt the code to Silicon which no longer
> allows to make pages writable and executable. Few extra operations are
> required.

There are two approaches for doing that. One is to create a writable
mapping and an executable mapping of the same memory. Like this code,
which also works on SELinux and HardenedBSD:

#include <fcntl.h>
#include <stdlib.h>
/* Declare getpagesize().  */
#include <unistd.h>
/* Declare mmap().  */
#include <sys/mman.h>
main ()
  unsigned int pagesize = getpagesize ();
  int fd;
  char *pw;
  char *px;
  fd = open ("/tmp/tinycc2873312.data", O_CREAT | O_RDWR | O_TRUNC, 0700);
  if (fd < 0)
    return 1;
  if (ftruncate (fd, pagesize) < 0)
    return 2;
  pw = (char *) mmap (NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0);
  if (pw == (char*) -1)
    return 3;
  ((unsigned int *)pw)[5] = 0xD65F03C0U;
  px = (char *) mmap (NULL, pagesize, PROT_READ | PROT_EXEC, MAP_SHARED | MAP_FILE, fd, 0);
  if (px == (char*) -1)
    return 4;
  if (((unsigned int *)px)[5] != 0xD65F03C0U)
    return 5;
  ((void (*) (void)) (px + 20)) ();
  return 0;

The difference between macOS and the other OSes is that with the other OSes
you can unlink() the file before the mmap() calls, whereas on macOS you need
to keep the file visible in the file system (and hopefully clean it up when
or before your program terminates).

The other way is to buy into Apple's "let's restrict user freedom in the
name of security" approach, namely accept code signing as a measure to gain
access to certain APIs [1][2].


[1] https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon
[2] https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit

More information about the cfarm-users mailing list