summaryrefslogtreecommitdiffstats
path: root/build/mac
diff options
context:
space:
mode:
Diffstat (limited to 'build/mac')
-rwxr-xr-xbuild/mac/change_mach_o_flags.py (renamed from build/mac/make_heap_non_executable.py)79
-rwxr-xr-xbuild/mac/change_mach_o_flags_from_xcode.sh14
-rwxr-xr-xbuild/mac/make_heap_non_executable_from_xcode.sh15
3 files changed, 75 insertions, 33 deletions
diff --git a/build/mac/make_heap_non_executable.py b/build/mac/change_mach_o_flags.py
index 507403a..1dfe07f 100755
--- a/build/mac/make_heap_non_executable.py
+++ b/build/mac/change_mach_o_flags.py
@@ -4,10 +4,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Usage: make_heap_non_executable.py <executable_path>
+# Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executable_path>
#
# Arranges for the executable at |executable_path| to have its data (heap)
-# pages protected to prevent execution on Mac OS X 10.7 ("Lion").
+# pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have
+# the PIE (position independent executable) bit set to enable ASLR (address
+# space layout randomization). With --executable-heap or --no-pie, the
+# respective bits are cleared instead of set, making the heap executable or
+# disabling PIE/ASLR.
+#
+# This script is able to operate on thin (single-architecture) Mach-O files
+# and fat (universal, multi-architecture) files. When operating on fat files,
+# it will set or clear the bits for each architecture contained therein.
+#
+# NON-EXECUTABLE HEAP
#
# Traditionally in Mac OS X, 32-bit processes did not have data pages set to
# prohibit execution. Although user programs could call mprotect and
@@ -47,12 +57,24 @@
# with appropriate protection even when vm.allow_data_exec has been tampered
# with.
#
-# This script is able to operate on thin (single-architecture) Mach-O files
-# and fat (universal, multi-architecture) files. When operating on fat files,
-# it will set the MH_NO_HEAP_EXECUTION bit for each architecture contained
-# therein.
+# POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION
+#
+# This script sets or clears the MH_PIE bit in an executable's Mach-O header,
+# enabling or disabling position independence on Mac OS X 10.5 and later.
+# Processes running position-independent executables have varying levels of
+# ASLR protection depending on the OS release. The main executable's load
+# address, shared library load addresess, and the heap and stack base
+# addresses may be randomized. Position-independent executables are produced
+# by supplying the -pie flag to the linker (or defeated by supplying -no_pie).
+# Executables linked with a deployment target of 10.7 or higher have PIE on
+# by default.
+#
+# This script is never strictly needed during the build to enable PIE, as all
+# linkers used are recent enough to support -pie. However, it's used to
+# disable the PIE bit as needed on already-linked executables.
+import optparse
import os
import struct
import sys
@@ -68,7 +90,8 @@ MH_CIGAM = 0xcefaedfe
MH_MAGIC_64 = 0xfeedfacf
MH_CIGAM_64 = 0xcffaedfe
MH_EXECUTE = 0x2
-MH_NO_HEAP_EXECUTION = 0x1000000
+MH_PIE = 0x00200000
+MH_NO_HEAP_EXECUTION = 0x01000000
class MachOError(Exception):
@@ -150,14 +173,15 @@ def WriteUInt32(file, uint32, endian):
file.write(bytes)
-def HandleMachOFile(file, offset=0):
+def HandleMachOFile(file, options, offset=0):
"""Seeks the file-like |file| object to |offset|, reads its |mach_header|,
and rewrites the header's |flags| field if appropriate. The header's
endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported
(mach_header and mach_header_64). Raises MachOError if used on a header that
does not have a known magic number or is not of type MH_EXECUTE. The
- MH_NO_HEAP_EXECUTION is set in the |flags| field and written to |file| if
- not already set. If already set, nothing is written."""
+ MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field
+ according to |options| and written to |file| if any changes need to be made.
+ If already set or clear as specified by |options|, nothing is written."""
CheckedSeek(file, offset)
magic = ReadUInt32(file, '<')
@@ -178,13 +202,24 @@ def HandleMachOFile(file, offset=0):
'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
(offset, filetype)
- if not flags & MH_NO_HEAP_EXECUTION:
+ original_flags = flags
+
+ if options.no_heap_execution:
flags |= MH_NO_HEAP_EXECUTION
+ else:
+ flags &= ~MH_NO_HEAP_EXECUTION
+
+ if options.pie:
+ flags |= MH_PIE
+ else:
+ flags &= ~MH_PIE
+
+ if flags != original_flags:
CheckedSeek(file, offset + 24)
WriteUInt32(file, flags, endian)
-def HandleFatFile(file, fat_offset=0):
+def HandleFatFile(file, options, fat_offset=0):
"""Seeks the file-like |file| object to |offset| and loops over its
|fat_header| entries, calling HandleMachOFile for each."""
@@ -201,25 +236,33 @@ def HandleFatFile(file, fat_offset=0):
# HandleMachOFile will seek around. Come back here after calling it, in
# case it sought.
fat_arch_offset = file.tell()
- HandleMachOFile(file, offset)
+ HandleMachOFile(file, options, offset)
CheckedSeek(file, fat_arch_offset)
def main(me, args):
- if len(args) != 1:
- print >>sys.stderr, 'usage: %s <executable_path>' % me
+ parser = optparse.OptionParser('%prog [options] <executable_path>')
+ parser.add_option('--executable-heap', action='store_false',
+ dest='no_heap_execution', default=True,
+ help='Clear the MH_NO_HEAP_EXECUTION bit')
+ parser.add_option('--no-pie', action='store_false',
+ dest='pie', default=True,
+ help='Clear the MH_PIE bit')
+ (options, loose_args) = parser.parse_args(args)
+ if len(loose_args) != 1:
+ parser.print_usage()
return 1
- executable_path = args[0]
+ executable_path = loose_args[0]
executable_file = open(executable_path, 'rb+')
magic = ReadUInt32(executable_file, '<')
if magic == FAT_CIGAM:
# Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian.
- HandleFatFile(executable_file)
+ HandleFatFile(executable_file, options)
elif magic == MH_MAGIC or magic == MH_CIGAM or \
magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
- HandleMachOFile(executable_file)
+ HandleMachOFile(executable_file, options)
else:
raise MachOError, '%s is not a Mach-O or fat file' % executable_file
diff --git a/build/mac/change_mach_o_flags_from_xcode.sh b/build/mac/change_mach_o_flags_from_xcode.sh
new file mode 100755
index 0000000..ab3ee49
--- /dev/null
+++ b/build/mac/change_mach_o_flags_from_xcode.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a small wrapper script around change_mach_o_flags.py allowing it to
+# be invoked easily from Xcode. change_mach_o_flags.py expects its arguments
+# on the command line, but Xcode puts its parameters in the environment.
+
+set -e
+
+exec "$(dirname "${0}")/change_mach_o_flags.py" \
+ "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
diff --git a/build/mac/make_heap_non_executable_from_xcode.sh b/build/mac/make_heap_non_executable_from_xcode.sh
deleted file mode 100755
index adfc25d..0000000
--- a/build/mac/make_heap_non_executable_from_xcode.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is a small wrapper script around make_heap_non_executable.py allowing
-# it to be invoked easily from Xcode. make_heap_non_executable.py expects its
-# argument on the command line, and Xcode puts all of its parameters in the
-# environment.
-
-set -e
-
-exec "$(dirname "${0}")/make_heap_non_executable.py" \
- "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"