diff options
Diffstat (limited to 'build/mac')
-rwxr-xr-x | build/mac/change_mach_o_flags.py (renamed from build/mac/make_heap_non_executable.py) | 79 | ||||
-rwxr-xr-x | build/mac/change_mach_o_flags_from_xcode.sh | 14 | ||||
-rwxr-xr-x | build/mac/make_heap_non_executable_from_xcode.sh | 15 |
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}" |