Chromium Code Reviews| 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 ''' | |
|
jvoung (off chromium)
2015/03/24 20:47:25
""" instead of ''' for docstrings and oneliner sum
Derek Schuff
2015/03/24 23:15:15
Done.
| |
| 169 This is a kind of lint check to ensure that the LLVM assembler's option for | |
| 170 hiding the sandbox base address on x86-64 is being used in all code compiled | |
| 171 into the IRT. It is only a heuristic intended to prevent accidental changes | |
| 172 in the IRT or toolchain build, and is not exhaustive. It is a stopgap until | |
| 173 we can fix https://code.google.com/p/nativeclient/issues/detail?id=3596 | |
| 174 ''' | |
| 175 cmd = [self.objdump_cmd, '-d', self.output] | |
| 176 output = self.Run(cmd, get_output=True) | |
| 177 # Disallow callq, all movs variants, all stos variants | |
| 178 # (objdump always disassembles 'call' as 'callq' in x86-64) | |
| 179 test_regex = r'\scallq\s|\smovs[bwlq]\s|\sstos[bwlq]\s' | |
| 180 # Disallow reads from rsp (other than %rsp,%rpb), and from rbp | |
| 181 test_regex += r'|[^(]%rsp,(?!%rbp)|[^(]%rbp,' | |
|
jvoung (off chromium)
2015/03/24 20:47:25
Hmm, so the trailing "," is required? What about
Derek Schuff
2015/03/24 23:15:15
It needs the trailing comma so that it doesn't cat
| |
| 182 # Disallow reads from %r11 or uses as a base register | |
| 183 test_regex += r'|%r11,' | |
| 184 # All indirect jumps must be through r11 | |
| 185 test_regex += r'|jmpq\s+\*%r(?!11)' | |
| 186 matched = re.search(test_regex, output) | |
| 187 if matched: | |
| 188 print 'The following instructions may reveal the sandbox base address:' | |
| 189 for line in output.splitlines(): | |
|
jvoung (off chromium)
2015/03/24 20:47:25
Hmm... can the splitlines() be done earlier?
My m
Derek Schuff
2015/03/24 23:15:15
I was attempting to avoid splitlines in the non-er
jvoung (off chromium)
2015/03/25 16:53:49
Okay sounds fine.
| |
| 190 match = re.search(test_regex, line) | |
|
jvoung (off chromium)
2015/03/24 20:47:25
3 space indent -> 2 space indent
Derek Schuff
2015/03/24 23:15:15
Done.
| |
| 191 if match: | |
| 192 print line | |
|
jvoung (off chromium)
2015/03/24 20:47:25
1 space indent -> 2 space indent
Derek Schuff
2015/03/24 23:15:15
Done.
| |
| 193 raise Error('IRT sandbox base address hiding lint check failed') | |
| 194 | |
| 195 else: | |
| 196 self.Log('Sandbox base address hiding lint check passed') | |
| 197 | |
| 165 | 198 |
| 166 def Main(): | 199 def Main(): |
| 167 parser = argparse.ArgumentParser() | 200 parser = argparse.ArgumentParser() |
| 168 parser.add_argument('-o', '--output', dest='output', required=True, | 201 parser.add_argument('-o', '--output', dest='output', required=True, |
| 169 help='Output filename') | 202 help='Output filename') |
| 170 parser.add_argument('--tls-edit', dest='tls_edit', required=True, | 203 parser.add_argument('--tls-edit', dest='tls_edit', required=True, |
| 171 help='Path of tls edit utility') | 204 help='Path of tls edit utility') |
| 172 parser.add_argument('--link-cmd', dest='link_cmd', required=True, | 205 parser.add_argument('--link-cmd', dest='link_cmd', required=True, |
| 173 help='Path of linker utility') | 206 help='Path of linker utility') |
| 174 parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, | 207 parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, |
| 175 help='Path of readelf utility') | 208 help='Path of readelf utility') |
| 176 parser.add_argument('-v', '--verbose', dest='verbose', default=False, | 209 parser.add_argument('--objdump-cmd', dest='objdump_cmd', required=False, |
| 210 help='Path of objdump utility') | |
| 211 parser.add_argument('-v', '--verbose', dest='verbose', default=True, | |
| 177 help='Enable verbosity', action='store_true') | 212 help='Enable verbosity', action='store_true') |
| 178 parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', | 213 parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', |
| 179 action='store_true', default=False, | 214 action='store_true', default=False, |
| 180 help='Indicate that toolchain commands are scripts') | 215 help='Indicate that toolchain commands are scripts') |
| 216 parser.add_argument('--sandbox-base-hiding-check', | |
| 217 dest='sandbox_base_hiding_check', action='store_true', | |
| 218 default=False) | |
|
jvoung (off chromium)
2015/03/24 20:47:25
help message?
| |
| 181 args, remaining_args = parser.parse_known_args() | 219 args, remaining_args = parser.parse_known_args() |
| 182 linker = IRTLinker(args) | 220 linker = IRTLinker(args) |
| 183 linker.Link(remaining_args) | 221 linker.Link(remaining_args) |
| 222 if args.sandbox_base_hiding_check: | |
| 223 linker.SandboxBaseCheck() | |
| 184 return 0 | 224 return 0 |
| 185 | 225 |
| 186 | 226 |
| 187 if __name__ == '__main__': | 227 if __name__ == '__main__': |
| 188 sys.exit(Main()) | 228 sys.exit(Main()) |
| OLD | NEW |