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.)
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?