OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright 2014 The Native Client Authors. All rights reserved. | 2 # Copyright 2014 The Native Client Authors. All rights reserved. |
3 # 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 |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Script for linking the NaCl IRT and IRT core. | 6 """Script for linking the NaCl IRT and IRT core. |
7 | 7 |
8 This module will take care of linking the NaCl IRT. Compiling the libraries | 8 This module will take care of linking the NaCl IRT. Compiling the libraries |
9 and object files that go into the NaCl IRT is done outside of this script. | 9 and object files that go into the NaCl IRT is done outside of this script. |
10 | 10 |
11 Linking is factored out because the IRT has specific requirements for | 11 Linking is factored out because the IRT has specific requirements for |
12 where to place the text vs data segments, and also requires editting how | 12 where to place the text vs data segments, and also requires editting how |
13 TLS access is done. Thus, it's more complicated than the usual linking. | 13 TLS access is done. Thus, it's more complicated than the usual linking. |
14 """ | 14 """ |
15 | 15 |
16 import argparse | 16 import argparse |
17 import os | 17 import os |
| 18 import re |
18 import sys | 19 import sys |
19 | 20 |
20 from build_nexe_tools import (CommandRunner, Error, FixPath, MakeDir) | 21 from build_nexe_tools import (CommandRunner, Error, FixPath, MakeDir) |
21 | 22 |
22 | 23 |
23 class IRTLinker(CommandRunner): | 24 class IRTLinker(CommandRunner): |
24 """Builder object that generates build command-lines and runs them. | 25 """Builder object that generates build command-lines and runs them. |
25 """ | 26 """ |
26 | 27 |
27 def __init__(self, options): | 28 def __init__(self, options): |
28 super(IRTLinker, self).__init__(options) | 29 super(IRTLinker, self).__init__(options) |
29 # IRT constraints for auto layout. | 30 # IRT constraints for auto layout. |
30 # IRT text can only go up to 256MB. Addresses after that are for data. | 31 # IRT text can only go up to 256MB. Addresses after that are for data. |
31 # Reserve an extra page because: | 32 # Reserve an extra page because: |
32 # * sel_ldr requires a HLT sled at the end of the dynamic code area; | 33 # * sel_ldr requires a HLT sled at the end of the dynamic code area; |
33 # * dynamic_load_test currently tests loading at the end of the dynamic | 34 # * dynamic_load_test currently tests loading at the end of the dynamic |
34 # code area. | 35 # code area. |
35 self.irt_text_max = 0x10000000 - 0x10000 | 36 self.irt_text_max = 0x10000000 - 0x10000 |
36 # Data can only go up to the sandbox_top - sizeof(stack). | 37 # Data can only go up to the sandbox_top - sizeof(stack). |
37 # NaCl allocates 16MB for the initial thread's stack (see | 38 # NaCl allocates 16MB for the initial thread's stack (see |
38 # NACL_DEFAULT_STACK_MAX in sel_ldr.h). | 39 # NACL_DEFAULT_STACK_MAX in sel_ldr.h). |
39 # Assume sandbox_top is 1GB, since even on x86-64 the limit would | 40 # Assume sandbox_top is 1GB, since even on x86-64 the limit would |
40 # only be 2GB (rip-relative references can only be +/- 2GB). | 41 # only be 2GB (rip-relative references can only be +/- 2GB). |
41 sandbox_top = 0x40000000 | 42 sandbox_top = 0x40000000 |
42 self.irt_data_max = sandbox_top - (16 << 20) | 43 self.irt_data_max = sandbox_top - (16 << 20) |
43 self.output = options.output | 44 self.output = options.output |
44 self.link_cmd = options.link_cmd | 45 self.link_cmd = options.link_cmd |
45 self.readelf_cmd = options.readelf_cmd | 46 self.readelf_cmd = options.readelf_cmd |
| 47 self.objdump_cmd = options.objdump_cmd |
46 self.tls_edit = options.tls_edit | 48 self.tls_edit = options.tls_edit |
47 self.SetCommandsAreScripts(options.commands_are_scripts) | 49 self.SetCommandsAreScripts(options.commands_are_scripts) |
48 | 50 |
49 def GetIRTLayout(self, irt_file): | 51 def GetIRTLayout(self, irt_file): |
50 """Check if the IRT's data and text segment fit layout constraints and | 52 """Check if the IRT's data and text segment fit layout constraints and |
51 get sizes of the IRT's text and data segments. | 53 get sizes of the IRT's text and data segments. |
52 | 54 |
53 Returns a tuple containing: | 55 Returns a tuple containing: |
54 * whether the IRT data/text top addresses fit within the max limit | 56 * whether the IRT data/text top addresses fit within the max limit |
55 * current data/text top addrs | 57 * current data/text top addrs |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 'text_top=0x%x and data_top=0x%x\n' % ( | 157 'text_top=0x%x and data_top=0x%x\n' % ( |
156 text_top, data_top)) | 158 text_top, data_top)) |
157 self.Log('IRT layout fits: text_top=0x%x and data_top=0x%x' % | 159 self.Log('IRT layout fits: text_top=0x%x and data_top=0x%x' % |
158 (text_top, data_top)) | 160 (text_top, data_top)) |
159 | 161 |
160 tls_edit_cmd = [FixPath(self.tls_edit), pre_tls_edit_out, out] | 162 tls_edit_cmd = [FixPath(self.tls_edit), pre_tls_edit_out, out] |
161 tls_edit_err = self.Run(tls_edit_cmd, possibly_script=False) | 163 tls_edit_err = self.Run(tls_edit_cmd, possibly_script=False) |
162 if tls_edit_err: | 164 if tls_edit_err: |
163 raise Error('FAILED with %d: %s' % (err, ' '.join(tls_edit_cmd))) | 165 raise Error('FAILED with %d: %s' % (err, ' '.join(tls_edit_cmd))) |
164 | 166 |
| 167 def SandboxBaseCheck(self): |
| 168 """ |
| 169 Check that sandbox base address is not revealed. |
| 170 |
| 171 This is a kind of lint check to ensure that the LLVM assembler's option for |
| 172 hiding the sandbox base address on x86-64 is being used in all code compiled |
| 173 into the IRT. It is only a heuristic intended to prevent accidental changes |
| 174 in the IRT or toolchain build, and is not exhaustive. It is a stopgap until |
| 175 we can fix https://code.google.com/p/nativeclient/issues/detail?id=3596 |
| 176 """ |
| 177 cmd = [self.objdump_cmd, '-d', self.output] |
| 178 output = self.Run(cmd, get_output=True) |
| 179 # Disallow callq, all movs variants, all stos variants |
| 180 # (objdump always disassembles 'call' as 'callq' in x86-64) |
| 181 test_regex = r'\scallq\s|\smovs[bwlq]\s|\sstos[bwlq]\s' |
| 182 # Disallow reads/pushes from rsp (other than %rsp,%rpb), and from rbp |
| 183 test_regex += r'|[^(]%rsp,(?!%rbp)|[^(]%rbp,|push\s+%r[sb]p' |
| 184 # Disallow reads from %r11 or uses as a base register |
| 185 test_regex += r'|%r11,' |
| 186 # All indirect jumps must be through r11 |
| 187 test_regex += r'|jmpq\s+\*%r(?!11)' |
| 188 matched = re.search(test_regex, output) |
| 189 if matched: |
| 190 print 'The following instructions may reveal the sandbox base address:' |
| 191 lines_printed = 0 |
| 192 lines_printed_limit = 50 |
| 193 for line in output.splitlines(): |
| 194 match = re.search(test_regex, line) |
| 195 if match and lines_printed < lines_printed_limit: |
| 196 lines_printed += 1 |
| 197 print line |
| 198 if lines_printed == lines_printed_limit: |
| 199 print '(additional lines not printed)' |
| 200 print 'ran', cmd |
| 201 raise Error('IRT sandbox base address hiding lint check failed') |
| 202 |
| 203 else: |
| 204 self.Log('Sandbox base address hiding lint check passed') |
| 205 |
165 | 206 |
166 def Main(): | 207 def Main(): |
167 parser = argparse.ArgumentParser() | 208 parser = argparse.ArgumentParser() |
168 parser.add_argument('-o', '--output', dest='output', required=True, | 209 parser.add_argument('-o', '--output', dest='output', required=True, |
169 help='Output filename') | 210 help='Output filename') |
170 parser.add_argument('--tls-edit', dest='tls_edit', required=True, | 211 parser.add_argument('--tls-edit', dest='tls_edit', required=True, |
171 help='Path of tls edit utility') | 212 help='Path of tls edit utility') |
172 parser.add_argument('--link-cmd', dest='link_cmd', required=True, | 213 parser.add_argument('--link-cmd', dest='link_cmd', required=True, |
173 help='Path of linker utility') | 214 help='Path of linker utility') |
174 parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, | 215 parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, |
175 help='Path of readelf utility') | 216 help='Path of readelf utility') |
| 217 parser.add_argument('--objdump-cmd', dest='objdump_cmd', required=False, |
| 218 help='Path of objdump utility') |
176 parser.add_argument('-v', '--verbose', dest='verbose', default=False, | 219 parser.add_argument('-v', '--verbose', dest='verbose', default=False, |
177 help='Enable verbosity', action='store_true') | 220 help='Enable verbosity', action='store_true') |
178 parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', | 221 parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', |
179 action='store_true', default=False, | 222 action='store_true', default=False, |
180 help='Indicate that toolchain commands are scripts') | 223 help='Indicate that toolchain commands are scripts') |
| 224 parser.add_argument('--sandbox-base-hiding-check', |
| 225 dest='sandbox_base_hiding_check', action='store_true', |
| 226 default=False) |
181 args, remaining_args = parser.parse_known_args() | 227 args, remaining_args = parser.parse_known_args() |
182 linker = IRTLinker(args) | 228 linker = IRTLinker(args) |
183 linker.Link(remaining_args) | 229 linker.Link(remaining_args) |
| 230 if args.sandbox_base_hiding_check: |
| 231 linker.SandboxBaseCheck() |
184 return 0 | 232 return 0 |
185 | 233 |
186 | 234 |
187 if __name__ == '__main__': | 235 if __name__ == '__main__': |
188 sys.exit(Main()) | 236 sys.exit(Main()) |
OLD | NEW |