OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/env python |
2 | |
3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 4 # found in the LICENSE file. |
6 | 5 |
7 # Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executable_path> | 6 """Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executablepath> |
8 # | |
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"), 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 | |
21 # | |
22 # Traditionally in Mac OS X, 32-bit processes did not have data pages set to | |
23 # prohibit execution. Although user programs could call mprotect and | |
24 # mach_vm_protect to deny execution of code in data pages, the kernel would | |
25 # silently ignore such requests without updating the page tables, and the | |
26 # hardware would happily execute code on such pages. 64-bit processes were | |
27 # always given proper hardware protection of data pages. This behavior was | |
28 # controllable on a system-wide level via the vm.allow_data_exec sysctl, which | |
29 # is set by default to 1. The bit with value 1 (set by default) allows code | |
30 # execution on data pages for 32-bit processes, and the bit with value 2 | |
31 # (clear by default) does the same for 64-bit processes. | |
32 # | |
33 # In Mac OS X 10.7, executables can "opt in" to having hardware protection | |
34 # against code execution on data pages applied. This is done by setting a new | |
35 # bit in the |flags| field of an executable's |mach_header|. When | |
36 # MH_NO_HEAP_EXECUTION is set, proper protections will be applied, regardless | |
37 # of the setting of vm.allow_data_exec. See xnu-1699.22.73/osfmk/vm/vm_map.c | |
38 # override_nx and xnu-1699.22.73/bsd/kern/mach_loader.c load_machfile. | |
39 # | |
40 # The Apple toolchain has been revised to set the MH_NO_HEAP_EXECUTION when | |
41 # producing executables, provided that -allow_heap_execute is not specified | |
42 # at link time. Only linkers shipping with Xcode 4.0 and later (ld64-123.2 and | |
43 # later) have this ability. See ld64-123.2.1/src/ld/Options.cpp | |
44 # Options::reconfigureDefaults() and | |
45 # ld64-123.2.1/src/ld/HeaderAndLoadCommands.hpp | |
46 # HeaderAndLoadCommandsAtom<A>::flags(). | |
47 # | |
48 # This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is | |
49 # intended for use with executables produced by a linker that predates Apple's | |
50 # modifications to set this bit itself. It is also useful for setting this bit | |
51 # for non-i386 executables, including x86_64 executables. Apple's linker only | |
52 # sets it for 32-bit i386 executables, presumably under the assumption that | |
53 # the value of vm.allow_data_exec is set in stone. However, if someone were to | |
54 # change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run | |
55 # without hardware protection against code execution on data pages. This | |
56 # script can set the bit for x86_64 executables, guaranteeing that they run | |
57 # with appropriate protection even when vm.allow_data_exec has been tampered | |
58 # with. | |
59 # | |
60 # POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION | |
61 # | |
62 # This script sets or clears the MH_PIE bit in an executable's Mach-O header, | |
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. | |
75 | 7 |
| 8 Arranges for the executable at |executable_path| to have its data (heap) |
| 9 pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have |
| 10 the PIE (position independent executable) bit set to enable ASLR (address |
| 11 space layout randomization). With --executable-heap or --no-pie, the |
| 12 respective bits are cleared instead of set, making the heap executable or |
| 13 disabling PIE/ASLR. |
| 14 |
| 15 This script is able to operate on thin (single-architecture) Mach-O files |
| 16 and fat (universal, multi-architecture) files. When operating on fat files, |
| 17 it will set or clear the bits for each architecture contained therein. |
| 18 |
| 19 NON-EXECUTABLE HEAP |
| 20 |
| 21 Traditionally in Mac OS X, 32-bit processes did not have data pages set to |
| 22 prohibit execution. Although user programs could call mprotect and |
| 23 mach_vm_protect to deny execution of code in data pages, the kernel would |
| 24 silently ignore such requests without updating the page tables, and the |
| 25 hardware would happily execute code on such pages. 64-bit processes were |
| 26 always given proper hardware protection of data pages. This behavior was |
| 27 controllable on a system-wide level via the vm.allow_data_exec sysctl, which |
| 28 is set by default to 1. The bit with value 1 (set by default) allows code |
| 29 execution on data pages for 32-bit processes, and the bit with value 2 |
| 30 (clear by default) does the same for 64-bit processes. |
| 31 |
| 32 In Mac OS X 10.7, executables can "opt in" to having hardware protection |
| 33 against code execution on data pages applied. This is done by setting a new |
| 34 bit in the |flags| field of an executable's |mach_header|. When |
| 35 MH_NO_HEAP_EXECUTION is set, proper protections will be applied, regardless |
| 36 of the setting of vm.allow_data_exec. See xnu-1699.22.73/osfmk/vm/vm_map.c |
| 37 override_nx and xnu-1699.22.73/bsd/kern/mach_loader.c load_machfile. |
| 38 |
| 39 The Apple toolchain has been revised to set the MH_NO_HEAP_EXECUTION when |
| 40 producing executables, provided that -allow_heap_execute is not specified |
| 41 at link time. Only linkers shipping with Xcode 4.0 and later (ld64-123.2 and |
| 42 later) have this ability. See ld64-123.2.1/src/ld/Options.cpp |
| 43 Options::reconfigureDefaults() and |
| 44 ld64-123.2.1/src/ld/HeaderAndLoadCommands.hpp |
| 45 HeaderAndLoadCommandsAtom<A>::flags(). |
| 46 |
| 47 This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is |
| 48 intended for use with executables produced by a linker that predates Apple's |
| 49 modifications to set this bit itself. It is also useful for setting this bit |
| 50 for non-i386 executables, including x86_64 executables. Apple's linker only |
| 51 sets it for 32-bit i386 executables, presumably under the assumption that |
| 52 the value of vm.allow_data_exec is set in stone. However, if someone were to |
| 53 change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run |
| 54 without hardware protection against code execution on data pages. This |
| 55 script can set the bit for x86_64 executables, guaranteeing that they run |
| 56 with appropriate protection even when vm.allow_data_exec has been tampered |
| 57 with. |
| 58 |
| 59 POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION |
| 60 |
| 61 This script sets or clears the MH_PIE bit in an executable's Mach-O header, |
| 62 enabling or disabling position independence on Mac OS X 10.5 and later. |
| 63 Processes running position-independent executables have varying levels of |
| 64 ASLR protection depending on the OS release. The main executable's load |
| 65 address, shared library load addresess, and the heap and stack base |
| 66 addresses may be randomized. Position-independent executables are produced |
| 67 by supplying the -pie flag to the linker (or defeated by supplying -no_pie). |
| 68 Executables linked with a deployment target of 10.7 or higher have PIE on |
| 69 by default. |
| 70 |
| 71 This script is never strictly needed during the build to enable PIE, as all |
| 72 linkers used are recent enough to support -pie. However, it's used to |
| 73 disable the PIE bit as needed on already-linked executables. |
| 74 """ |
76 | 75 |
77 import optparse | 76 import optparse |
78 import os | 77 import os |
79 import struct | 78 import struct |
80 import sys | 79 import sys |
81 | 80 |
82 | 81 |
83 # <mach-o/fat.h> | 82 # <mach-o/fat.h> |
84 FAT_MAGIC = 0xcafebabe | 83 FAT_MAGIC = 0xcafebabe |
85 FAT_CIGAM = 0xbebafeca | 84 FAT_CIGAM = 0xbebafeca |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 if magic == FAT_CIGAM: | 259 if magic == FAT_CIGAM: |
261 # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian. | 260 # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian. |
262 HandleFatFile(executable_file, options) | 261 HandleFatFile(executable_file, options) |
263 elif magic == MH_MAGIC or magic == MH_CIGAM or \ | 262 elif magic == MH_MAGIC or magic == MH_CIGAM or \ |
264 magic == MH_MAGIC_64 or magic == MH_CIGAM_64: | 263 magic == MH_MAGIC_64 or magic == MH_CIGAM_64: |
265 HandleMachOFile(executable_file, options) | 264 HandleMachOFile(executable_file, options) |
266 else: | 265 else: |
267 raise MachOError, '%s is not a Mach-O or fat file' % executable_file | 266 raise MachOError, '%s is not a Mach-O or fat file' % executable_file |
268 | 267 |
269 executable_file.close() | 268 executable_file.close() |
| 269 return 0 |
270 | 270 |
271 return 0 | |
272 | 271 |
273 if __name__ == '__main__': | 272 if __name__ == '__main__': |
274 sys.exit(main(sys.argv[0], sys.argv[1:])) | 273 sys.exit(main(sys.argv[0], sys.argv[1:])) |
OLD | NEW |