Documented way to disable ASLR on OS X?

Gareth Rees picture Gareth Rees · May 27, 2014 · Viewed 7.1k times · Source

On OS X 10.9 (Mavericks), it's possible to disable address space layout randomization for a single process if you launch the process by calling posix_spawn() and passing the undocumented attribute 0x100. Like this:

extern char **environ;
pid_t pid;
posix_spawnattr_t attr;

posix_spawnattr_init(&attr);
posix_spawnattr_setflags(&attr, 0x100);
posix_spawn(&pid, argv[0], NULL, &attr, argv, environ);

(This is reverse-engineered from Apple's GDB sources.)

The trouble with undocumented features like this is that they tend to disappear without notice. According to this Stack Overflow answer the dynamic linker dyld used to consult the environment variable DYLD_NO_PIE, but this does not work in 10.9; similarly the static linker apparently used to take a --no-pie option, but this is no longer the case.

So is there a documented way to disable ASLR?

(The reason why I need to disable ASLR is to ensure repeatability, when testing and debugging, of code whose behaviour depends on the addresses of objects, for example address-based hash tables and BIBOP-based memory managers.)

Answer

nmaier picture nmaier · Jun 14, 2014

Actually, there still is a -no_pie linker flag, but you might have thought it is actually called --no-pie.

Lets have a small test program:

#include <stdio.h>

const char *test = "test";

int main() {
  printf("%p\n", (void*)test);
  return 0;
}

And compile as usual first:

cc -o test-pie test-pie.c

And check the flags

$ otool -hv test-pie
test-pie:
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL LIB64     EXECUTE    16       1376   NOUNDEFS DYLDLINK TWOLEVEL PIE

Alright there is a PIE flag in there, let's verify

$ for x in $(seq 1 5); do echo -n "$x "; ./test-pie; done
1 0x10a447f96
2 0x10e3cbf96
3 0x1005daf96
4 0x10df50f96
5 0x104e63f96

That looks random enough.

Now, lets tell the linker we don't want PIE using -Wl,-no_pie:

cc -o test-nopie test-pie.c -Wl,-no_pie

Sure enough the PIE flag is gone:

$ otool -hv test-nopie
test-pie:
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL LIB64     EXECUTE    16       1376   NOUNDEFS DYLDLINK TWOLEVEL

And test:

$ for x in $(seq 1 5); do echo -n "$x "; ./test-nopie; done
1 0x100000f96
2 0x100000f96
3 0x100000f96
4 0x100000f96
5 0x100000f96

So we make the linker not add the PIE flag, and my Mavericks system seems to still abide by it.

FWIW, the PIE flag is defined and documented in /usr/include/mach-o/loader.h as MH_PIE.

There are tools all over the Internet to clear the PIE flag from existing binaries, e.g. http://src.chromium.org/svn/trunk/src/build/mac/change_mach_o_flags.py

While I cannot offer you a documented way to start a PIE-flagged binary without ASLR, since you want to test code, presumably your own, just linking your test programs with -no_pie or removing the PIE flag afterwards from your test binaries should suffice?