Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(466)

Side by Side Diff: build/mac/change_mach_o_flags.py

Issue 7714018: Give plug-in processes an executable heap and disable PIE/ASLR for Native (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/common.gypi ('k') | build/mac/change_mach_o_flags_from_xcode.sh » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 # Usage: make_heap_non_executable.py <executable_path> 7 # Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executable_path>
8 # 8 #
9 # Arranges for the executable at |executable_path| to have its data (heap) 9 # Arranges for the executable at |executable_path| to have its data (heap)
10 # pages protected to prevent execution on Mac OS X 10.7 ("Lion"). 10 # pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have
11 # the PIE (position independent executable) bit set to enable ASLR (address
12 # space layout randomization). With --executable-heap or --no-pie, the
13 # respective bits are cleared instead of set, making the heap executable or
14 # disabling PIE/ASLR.
15 #
16 # This script is able to operate on thin (single-architecture) Mach-O files
17 # and fat (universal, multi-architecture) files. When operating on fat files,
18 # it will set or clear the bits for each architecture contained therein.
19 #
20 # NON-EXECUTABLE HEAP
11 # 21 #
12 # Traditionally in Mac OS X, 32-bit processes did not have data pages set to 22 # Traditionally in Mac OS X, 32-bit processes did not have data pages set to
13 # prohibit execution. Although user programs could call mprotect and 23 # prohibit execution. Although user programs could call mprotect and
14 # mach_vm_protect to deny execution of code in data pages, the kernel would 24 # mach_vm_protect to deny execution of code in data pages, the kernel would
15 # silently ignore such requests without updating the page tables, and the 25 # silently ignore such requests without updating the page tables, and the
16 # hardware would happily execute code on such pages. 64-bit processes were 26 # hardware would happily execute code on such pages. 64-bit processes were
17 # always given proper hardware protection of data pages. This behavior was 27 # always given proper hardware protection of data pages. This behavior was
18 # controllable on a system-wide level via the vm.allow_data_exec sysctl, which 28 # controllable on a system-wide level via the vm.allow_data_exec sysctl, which
19 # is set by default to 1. The bit with value 1 (set by default) allows code 29 # is set by default to 1. The bit with value 1 (set by default) allows code
20 # execution on data pages for 32-bit processes, and the bit with value 2 30 # execution on data pages for 32-bit processes, and the bit with value 2
(...skipping 19 matching lines...) Expand all
40 # modifications to set this bit itself. It is also useful for setting this bit 50 # modifications to set this bit itself. It is also useful for setting this bit
41 # for non-i386 executables, including x86_64 executables. Apple's linker only 51 # for non-i386 executables, including x86_64 executables. Apple's linker only
42 # sets it for 32-bit i386 executables, presumably under the assumption that 52 # sets it for 32-bit i386 executables, presumably under the assumption that
43 # the value of vm.allow_data_exec is set in stone. However, if someone were to 53 # the value of vm.allow_data_exec is set in stone. However, if someone were to
44 # change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run 54 # change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run
45 # without hardware protection against code execution on data pages. This 55 # without hardware protection against code execution on data pages. This
46 # script can set the bit for x86_64 executables, guaranteeing that they run 56 # script can set the bit for x86_64 executables, guaranteeing that they run
47 # with appropriate protection even when vm.allow_data_exec has been tampered 57 # with appropriate protection even when vm.allow_data_exec has been tampered
48 # with. 58 # with.
49 # 59 #
50 # This script is able to operate on thin (single-architecture) Mach-O files 60 # POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION
51 # and fat (universal, multi-architecture) files. When operating on fat files, 61 #
52 # it will set the MH_NO_HEAP_EXECUTION bit for each architecture contained 62 # This script sets or clears the MH_PIE bit in an executable's Mach-O header,
53 # therein. 63 # enabling or disabling position independence on Mac OS X 10.5 and later.
64 # Processes running position-independent executables have varying levels of
65 # ASLR protection depending on the OS release. The main executable's load
66 # address, shared library load addresess, and the heap and stack base
67 # addresses may be randomized. Position-independent executables are produced
68 # by supplying the -pie flag to the linker (or defeated by supplying -no_pie).
69 # Executables linked with a deployment target of 10.7 or higher have PIE on
70 # by default.
71 #
72 # This script is never strictly needed during the build to enable PIE, as all
73 # linkers used are recent enough to support -pie. However, it's used to
74 # disable the PIE bit as needed on already-linked executables.
54 75
55 76
77 import optparse
56 import os 78 import os
57 import struct 79 import struct
58 import sys 80 import sys
59 81
60 82
61 # <mach-o/fat.h> 83 # <mach-o/fat.h>
62 FAT_MAGIC = 0xcafebabe 84 FAT_MAGIC = 0xcafebabe
63 FAT_CIGAM = 0xbebafeca 85 FAT_CIGAM = 0xbebafeca
64 86
65 # <mach-o/loader.h> 87 # <mach-o/loader.h>
66 MH_MAGIC = 0xfeedface 88 MH_MAGIC = 0xfeedface
67 MH_CIGAM = 0xcefaedfe 89 MH_CIGAM = 0xcefaedfe
68 MH_MAGIC_64 = 0xfeedfacf 90 MH_MAGIC_64 = 0xfeedfacf
69 MH_CIGAM_64 = 0xcffaedfe 91 MH_CIGAM_64 = 0xcffaedfe
70 MH_EXECUTE = 0x2 92 MH_EXECUTE = 0x2
71 MH_NO_HEAP_EXECUTION = 0x1000000 93 MH_PIE = 0x00200000
94 MH_NO_HEAP_EXECUTION = 0x01000000
72 95
73 96
74 class MachOError(Exception): 97 class MachOError(Exception):
75 """A class for exceptions thrown by this module.""" 98 """A class for exceptions thrown by this module."""
76 99
77 pass 100 pass
78 101
79 102
80 def CheckedSeek(file, offset): 103 def CheckedSeek(file, offset):
81 """Seeks the file-like object at |file| to offset |offset| and raises a 104 """Seeks the file-like object at |file| to offset |offset| and raises a
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 """Writes |uint32| as an unsinged 32-bit integer to the file-like |file| 166 """Writes |uint32| as an unsinged 32-bit integer to the file-like |file|
144 object, treating it as having endianness specified by |endian| (per the 167 object, treating it as having endianness specified by |endian| (per the
145 |struct| module).""" 168 |struct| module)."""
146 169
147 bytes = struct.pack(endian + 'I', uint32) 170 bytes = struct.pack(endian + 'I', uint32)
148 assert len(bytes) == 4 171 assert len(bytes) == 4
149 172
150 file.write(bytes) 173 file.write(bytes)
151 174
152 175
153 def HandleMachOFile(file, offset=0): 176 def HandleMachOFile(file, options, offset=0):
154 """Seeks the file-like |file| object to |offset|, reads its |mach_header|, 177 """Seeks the file-like |file| object to |offset|, reads its |mach_header|,
155 and rewrites the header's |flags| field if appropriate. The header's 178 and rewrites the header's |flags| field if appropriate. The header's
156 endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported 179 endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported
157 (mach_header and mach_header_64). Raises MachOError if used on a header that 180 (mach_header and mach_header_64). Raises MachOError if used on a header that
158 does not have a known magic number or is not of type MH_EXECUTE. The 181 does not have a known magic number or is not of type MH_EXECUTE. The
159 MH_NO_HEAP_EXECUTION is set in the |flags| field and written to |file| if 182 MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field
160 not already set. If already set, nothing is written.""" 183 according to |options| and written to |file| if any changes need to be made.
184 If already set or clear as specified by |options|, nothing is written."""
161 185
162 CheckedSeek(file, offset) 186 CheckedSeek(file, offset)
163 magic = ReadUInt32(file, '<') 187 magic = ReadUInt32(file, '<')
164 if magic == MH_MAGIC or magic == MH_MAGIC_64: 188 if magic == MH_MAGIC or magic == MH_MAGIC_64:
165 endian = '<' 189 endian = '<'
166 elif magic == MH_CIGAM or magic == MH_CIGAM_64: 190 elif magic == MH_CIGAM or magic == MH_CIGAM_64:
167 endian = '>' 191 endian = '>'
168 else: 192 else:
169 raise MachOError, \ 193 raise MachOError, \
170 'Mach-O file at offset %d has illusion of magic' % offset 194 'Mach-O file at offset %d has illusion of magic' % offset
171 195
172 CheckedSeek(file, offset) 196 CheckedSeek(file, offset)
173 magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \ 197 magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
174 ReadMachHeader(file, endian) 198 ReadMachHeader(file, endian)
175 assert magic == MH_MAGIC or magic == MH_MAGIC_64 199 assert magic == MH_MAGIC or magic == MH_MAGIC_64
176 if filetype != MH_EXECUTE: 200 if filetype != MH_EXECUTE:
177 raise MachOError, \ 201 raise MachOError, \
178 'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \ 202 'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
179 (offset, filetype) 203 (offset, filetype)
180 204
181 if not flags & MH_NO_HEAP_EXECUTION: 205 original_flags = flags
206
207 if options.no_heap_execution:
182 flags |= MH_NO_HEAP_EXECUTION 208 flags |= MH_NO_HEAP_EXECUTION
209 else:
210 flags &= ~MH_NO_HEAP_EXECUTION
211
212 if options.pie:
213 flags |= MH_PIE
214 else:
215 flags &= ~MH_PIE
216
217 if flags != original_flags:
183 CheckedSeek(file, offset + 24) 218 CheckedSeek(file, offset + 24)
184 WriteUInt32(file, flags, endian) 219 WriteUInt32(file, flags, endian)
185 220
186 221
187 def HandleFatFile(file, fat_offset=0): 222 def HandleFatFile(file, options, fat_offset=0):
188 """Seeks the file-like |file| object to |offset| and loops over its 223 """Seeks the file-like |file| object to |offset| and loops over its
189 |fat_header| entries, calling HandleMachOFile for each.""" 224 |fat_header| entries, calling HandleMachOFile for each."""
190 225
191 CheckedSeek(file, fat_offset) 226 CheckedSeek(file, fat_offset)
192 magic = ReadUInt32(file, '>') 227 magic = ReadUInt32(file, '>')
193 assert magic == FAT_MAGIC 228 assert magic == FAT_MAGIC
194 229
195 nfat_arch = ReadUInt32(file, '>') 230 nfat_arch = ReadUInt32(file, '>')
196 231
197 for index in xrange(0, nfat_arch): 232 for index in xrange(0, nfat_arch):
198 cputype, cpusubtype, offset, size, align = ReadFatArch(file) 233 cputype, cpusubtype, offset, size, align = ReadFatArch(file)
199 assert size >= 28 234 assert size >= 28
200 235
201 # HandleMachOFile will seek around. Come back here after calling it, in 236 # HandleMachOFile will seek around. Come back here after calling it, in
202 # case it sought. 237 # case it sought.
203 fat_arch_offset = file.tell() 238 fat_arch_offset = file.tell()
204 HandleMachOFile(file, offset) 239 HandleMachOFile(file, options, offset)
205 CheckedSeek(file, fat_arch_offset) 240 CheckedSeek(file, fat_arch_offset)
206 241
207 242
208 def main(me, args): 243 def main(me, args):
209 if len(args) != 1: 244 parser = optparse.OptionParser('%prog [options] <executable_path>')
210 print >>sys.stderr, 'usage: %s <executable_path>' % me 245 parser.add_option('--executable-heap', action='store_false',
246 dest='no_heap_execution', default=True,
247 help='Clear the MH_NO_HEAP_EXECUTION bit')
248 parser.add_option('--no-pie', action='store_false',
249 dest='pie', default=True,
250 help='Clear the MH_PIE bit')
251 (options, loose_args) = parser.parse_args(args)
252 if len(loose_args) != 1:
253 parser.print_usage()
211 return 1 254 return 1
212 255
213 executable_path = args[0] 256 executable_path = loose_args[0]
214 executable_file = open(executable_path, 'rb+') 257 executable_file = open(executable_path, 'rb+')
215 258
216 magic = ReadUInt32(executable_file, '<') 259 magic = ReadUInt32(executable_file, '<')
217 if magic == FAT_CIGAM: 260 if magic == FAT_CIGAM:
218 # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian. 261 # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian.
219 HandleFatFile(executable_file) 262 HandleFatFile(executable_file, options)
220 elif magic == MH_MAGIC or magic == MH_CIGAM or \ 263 elif magic == MH_MAGIC or magic == MH_CIGAM or \
221 magic == MH_MAGIC_64 or magic == MH_CIGAM_64: 264 magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
222 HandleMachOFile(executable_file) 265 HandleMachOFile(executable_file, options)
223 else: 266 else:
224 raise MachOError, '%s is not a Mach-O or fat file' % executable_file 267 raise MachOError, '%s is not a Mach-O or fat file' % executable_file
225 268
226 executable_file.close() 269 executable_file.close()
227 270
228 return 0 271 return 0
229 272
230 if __name__ == '__main__': 273 if __name__ == '__main__':
231 sys.exit(main(sys.argv[0], sys.argv[1:])) 274 sys.exit(main(sys.argv[0], sys.argv[1:]))
OLDNEW
« no previous file with comments | « build/common.gypi ('k') | build/mac/change_mach_o_flags_from_xcode.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698