Source code for mythril.analysis.module.modules.user_assertions

"""This module contains the detection code for potentially insecure low-level
calls."""

from mythril.analysis import solver
from mythril.analysis.issue_annotation import IssueAnnotation
from mythril.analysis.potential_issues import Issue
from mythril.analysis.swc_data import ASSERT_VIOLATION
from mythril.analysis.module.base import DetectionModule, EntryPoint
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.smt import Extract, And
from mythril.exceptions import UnsatError
import logging
import eth_abi

log = logging.getLogger(__name__)

DESCRIPTION = """

Search for reachable user-supplied exceptions.
Report a warning if an log message is emitted: 'emit AssertionFailed(string)'

"""

assertion_failed_hash = (
    0xB42604CB105A16C8F6DB8A41E6B00C0C1B4826465E8BC504B3EB3E88B3E6A4A0
)

mstore_pattern = "0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe"


[docs]class UserAssertions(DetectionModule): """This module searches for user supplied exceptions: emit AssertionFailed("Error").""" name = "A user-defined assertion has been triggered" swc_id = ASSERT_VIOLATION description = DESCRIPTION entry_point = EntryPoint.CALLBACK pre_hooks = ["LOG1", "MSTORE"] def _execute(self, state: GlobalState) -> None: """ :param state: :return: """ return self._analyze_state(state) def _analyze_state(self, state: GlobalState): """ :param state: :return: """ opcode = state.get_current_instruction()["opcode"] message = None if opcode == "MSTORE": value = state.mstate.stack[-2] if value.symbolic: return [] if mstore_pattern not in hex(value.value)[:126]: return [] message = "Failed property id {}".format(Extract(15, 0, value).value) else: topic, size, mem_start = state.mstate.stack[-3:] if topic.symbolic or topic.value != assertion_failed_hash: return [] if not mem_start.symbolic and not size.symbolic: try: message = eth_abi.decode_single( "string", bytes( state.mstate.memory[ mem_start.value + 32 : mem_start.value + size.value ] ), ).decode("utf8") except: pass try: transaction_sequence = solver.get_transaction_sequence( state, state.world_state.constraints ) if message: description_tail = ( "A user-provided assertion failed with the message '{}'".format( message ) ) else: description_tail = "A user-provided assertion failed." log.debug("MythX assertion emitted: {}".format(description_tail)) address = state.get_current_instruction()["address"] issue = Issue( contract=state.environment.active_account.contract_name, function_name=state.environment.active_function_name, address=address, swc_id=ASSERT_VIOLATION, title="Exception State", severity="Medium", description_head="A user-provided assertion failed.", description_tail=description_tail, bytecode=state.environment.code.bytecode, transaction_sequence=transaction_sequence, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) state.annotate( IssueAnnotation( detector=self, issue=issue, conditions=[And(*state.world_state.constraints)], ) ) return [issue] except UnsatError: log.debug("no model found") return []
detector = UserAssertions()