Fix check of solc metadata tail (#848)

* Fix check of solc metasata tail

* Remove debug print

* fix metadat tail removal

* Yet another loose end - fixed

* Better version parsing and review fixes

* Remove debug print

* pep8
This commit is contained in:
feliam 2018-04-17 18:58:58 -03:00 committed by GitHub
parent 71bf5d4f11
commit 92cfab3a42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,5 +1,5 @@
import string import string
import re
from . import Manticore from . import Manticore
from .manticore import ManticoreError from .manticore import ManticoreError
from .core.smtlib import ConstraintSet, Operators, solver, issymbolic, Array, Expression, Constant, operators from .core.smtlib import ConstraintSet, Operators, solver, issymbolic, Array, Expression, Constant, operators
@ -7,7 +7,7 @@ from .core.smtlib.visitors import arithmetic_simplify, pretty_print
from .platforms import evm from .platforms import evm
from .core.state import State from .core.state import State
import tempfile import tempfile
from subprocess import Popen, PIPE from subprocess import Popen, PIPE, check_output
from multiprocessing import Process, Queue from multiprocessing import Process, Queue
from Queue import Empty as EmptyQueue from Queue import Empty as EmptyQueue
import sha3 import sha3
@ -140,13 +140,9 @@ class UninitializedStorage(Detector):
def calculate_coverage(runtime_bytecode, seen): def calculate_coverage(runtime_bytecode, seen):
''' Calculates what percentage of runtime_bytecode has been seen ''' ''' Calculates what percentage of runtime_bytecode has been seen '''
end = None
if ''.join(runtime_bytecode[-44: -34]) == '\x00\xa1\x65\x62\x7a\x7a\x72\x30\x58\x20' \
and ''.join(runtime_bytecode[-2:]) == '\x00\x29':
end = -9 - 33 - 2 # Size of metadata at the end of most contracts
count, total = 0, 0 count, total = 0, 0
for i in evm.EVMAsm.disassemble_all(runtime_bytecode[:end]): bytecode = SolidityMetadata._without_metadata(runtime_bytecode)
for i in evm.EVMAsm.disassemble_all(bytecode):
if i.offset in seen: if i.offset in seen:
count += 1 count += 1
total += 1 total += 1
@ -167,13 +163,18 @@ class SolidityMetadata(object):
self.srcmap_runtime = self.__build_source_map(self.runtime_bytecode, srcmap_runtime) self.srcmap_runtime = self.__build_source_map(self.runtime_bytecode, srcmap_runtime)
self.srcmap = self.__build_source_map(self.init_bytecode, srcmap) self.srcmap = self.__build_source_map(self.init_bytecode, srcmap)
@staticmethod
def _without_metadata(bytecode):
end = None
if ''.join(bytecode[-43: -34]) == '\xa1\x65\x62\x7a\x7a\x72\x30\x58\x20' \
and ''.join(bytecode[-2:]) == '\x00\x29':
end = -9 - 32 - 2 # Size of metadata at the end of most contracts
return bytecode[:end]
def __build_source_map(self, bytecode, srcmap): def __build_source_map(self, bytecode, srcmap):
# https://solidity.readthedocs.io/en/develop/miscellaneous.html#source-mappings # https://solidity.readthedocs.io/en/develop/miscellaneous.html#source-mappings
new_srcmap = {} new_srcmap = {}
end = None bytecode = self._without_metadata(bytecode)
if ''.join(bytecode[-44: -34]) == '\x00\xa1\x65\x62\x7a\x7a\x72\x30\x58\x20' \
and ''.join(bytecode[-2:]) == '\x00\x29':
end = -9 - 33 - 2 # Size of metadata at the end of most contracts
asm_offset = 0 asm_offset = 0
asm_pos = 0 asm_pos = 0
@ -183,7 +184,7 @@ class SolidityMetadata(object):
f = int(md.get(2, 0)) f = int(md.get(2, 0))
j = md.get(3, None) j = md.get(3, None)
for i in evm.EVMAsm.disassemble_all(bytecode[:end]): for i in evm.EVMAsm.disassemble_all(bytecode):
if asm_pos in srcmap and len(srcmap[asm_pos]): if asm_pos in srcmap and len(srcmap[asm_pos]):
md = srcmap[asm_pos] md = srcmap[asm_pos]
if len(md): if len(md):
@ -206,20 +207,12 @@ class SolidityMetadata(object):
@property @property
def runtime_bytecode(self): def runtime_bytecode(self):
# Removes metadata from the tail of bytecode # Removes metadata from the tail of bytecode
end = None return self._without_metadata(self._runtime_bytecode)
if ''.join(self._runtime_bytecode[-44: -34]) == '\x00\xa1\x65\x62\x7a\x7a\x72\x30\x58\x20' \
and ''.join(self._runtime_bytecode[-2:]) == '\x00\x29':
end = -9 - 33 - 2 # Size of metadata at the end of most contracts
return self._runtime_bytecode[:end]
@property @property
def init_bytecode(self): def init_bytecode(self):
# Removes metadata from the tail of bytecode # Removes metadata from the tail of bytecode
end = None return self._without_metadata(self._init_bytecode)
if ''.join(self._init_bytecode[-44: -34]) == '\x00\xa1\x65\x62\x7a\x7a\x72\x30\x58\x20' \
and ''.join(self._init_bytecode[-2:]) == '\x00\x29':
end = -9 - 33 - 2 # Size of metadata at the end of most contracts
return self._init_bytecode[:end]
def get_source_for(self, asm_offset, runtime=True): def get_source_for(self, asm_offset, runtime=True):
''' Solidity source code snippet related to `asm_pos` evm bytecode offset. ''' Solidity source code snippet related to `asm_pos` evm bytecode offset.
@ -673,6 +666,19 @@ class ManticoreEVM(Manticore):
:return: name, source_code, bytecode, srcmap, srcmap_runtime, hashes :return: name, source_code, bytecode, srcmap, srcmap_runtime, hashes
""" """
solc = "solc" solc = "solc"
#check solc version
supported_versions = ('0.4.18', '0.4.21')
installed_version_output = check_output([solc, "--version"])
m = re.match(r".*Version: (?P<version>(?P<major>\d+)\.(?P<minor>\d+)\.(?P<build>\d+))\+(?P<commit>[^\s]+).*", installed_version_output, re.DOTALL | re.IGNORECASE)
installed_version = m.groupdict()['version']
if installed_version not in supported_versions:
#Fixme https://github.com/trailofbits/manticore/issues/847
#logger.warning("Unsupported solc version %s", installed_version)
pass
with tempfile.NamedTemporaryFile() as temp: with tempfile.NamedTemporaryFile() as temp:
temp.write(source_code) temp.write(source_code)
temp.flush() temp.flush()