| 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 |