Index: build/link_irt.py |
diff --git a/build/link_irt.py b/build/link_irt.py |
index c161f2f0445b658e97697adbf3ae5e614cc7f9e9..452fe97957d8aa86b7cdc28865b75c5fd6a2e59c 100644 |
--- a/build/link_irt.py |
+++ b/build/link_irt.py |
@@ -15,6 +15,7 @@ TLS access is done. Thus, it's more complicated than the usual linking. |
import argparse |
import os |
+import re |
import sys |
from build_nexe_tools import (CommandRunner, Error, FixPath, MakeDir) |
@@ -43,6 +44,7 @@ class IRTLinker(CommandRunner): |
self.output = options.output |
self.link_cmd = options.link_cmd |
self.readelf_cmd = options.readelf_cmd |
+ self.objdump_cmd = options.objdump_cmd |
self.tls_edit = options.tls_edit |
self.SetCommandsAreScripts(options.commands_are_scripts) |
@@ -162,6 +164,45 @@ class IRTLinker(CommandRunner): |
if tls_edit_err: |
raise Error('FAILED with %d: %s' % (err, ' '.join(tls_edit_cmd))) |
+ def SandboxBaseCheck(self): |
+ """ |
+ Check that sandbox base address is not revealed. |
+ |
+ This is a kind of lint check to ensure that the LLVM assembler's option for |
+ hiding the sandbox base address on x86-64 is being used in all code compiled |
+ into the IRT. It is only a heuristic intended to prevent accidental changes |
+ in the IRT or toolchain build, and is not exhaustive. It is a stopgap until |
+ we can fix https://code.google.com/p/nativeclient/issues/detail?id=3596 |
+ """ |
+ cmd = [self.objdump_cmd, '-d', self.output] |
+ output = self.Run(cmd, get_output=True) |
+ # Disallow callq, all movs variants, all stos variants |
+ # (objdump always disassembles 'call' as 'callq' in x86-64) |
+ test_regex = r'\scallq\s|\smovs[bwlq]\s|\sstos[bwlq]\s' |
+ # Disallow reads/pushes from rsp (other than %rsp,%rpb), and from rbp |
+ test_regex += r'|[^(]%rsp,(?!%rbp)|[^(]%rbp,|push\s+%r[sb]p' |
+ # Disallow reads from %r11 or uses as a base register |
+ test_regex += r'|%r11,' |
+ # All indirect jumps must be through r11 |
+ test_regex += r'|jmpq\s+\*%r(?!11)' |
+ matched = re.search(test_regex, output) |
+ if matched: |
+ print 'The following instructions may reveal the sandbox base address:' |
+ lines_printed = 0 |
+ lines_printed_limit = 50 |
+ for line in output.splitlines(): |
+ match = re.search(test_regex, line) |
+ if match and lines_printed < lines_printed_limit: |
+ lines_printed += 1 |
+ print line |
+ if lines_printed == lines_printed_limit: |
+ print '(additional lines not printed)' |
+ print 'ran', cmd |
+ raise Error('IRT sandbox base address hiding lint check failed') |
+ |
+ else: |
+ self.Log('Sandbox base address hiding lint check passed') |
+ |
def Main(): |
parser = argparse.ArgumentParser() |
@@ -173,14 +214,21 @@ def Main(): |
help='Path of linker utility') |
parser.add_argument('--readelf-cmd', dest='readelf_cmd', required=True, |
help='Path of readelf utility') |
+ parser.add_argument('--objdump-cmd', dest='objdump_cmd', required=False, |
+ help='Path of objdump utility') |
parser.add_argument('-v', '--verbose', dest='verbose', default=False, |
help='Enable verbosity', action='store_true') |
parser.add_argument('--commands-are-scripts', dest='commands_are_scripts', |
action='store_true', default=False, |
help='Indicate that toolchain commands are scripts') |
+ parser.add_argument('--sandbox-base-hiding-check', |
+ dest='sandbox_base_hiding_check', action='store_true', |
+ default=False) |
args, remaining_args = parser.parse_known_args() |
linker = IRTLinker(args) |
linker.Link(remaining_args) |
+ if args.sandbox_base_hiding_check: |
+ linker.SandboxBaseCheck() |
return 0 |