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

"""This module contains the detection code for predictable variable
dependence."""
import logging
from copy import copy
from mythril.analysis.issue_annotation import IssueAnnotation
from mythril.analysis.module.base import DetectionModule, EntryPoint
from mythril.analysis.report import Issue
from mythril.exceptions import UnsatError
from mythril.analysis import solver
from mythril.analysis.swc_data import TX_ORIGIN_USAGE
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.smt import And
from typing import List

log = logging.getLogger(__name__)


[docs]class TxOriginAnnotation: """Symbol annotation added to a variable that is initialized with a call to the ORIGIN instruction.""" def __init__(self) -> None: pass
[docs]class TxOrigin(DetectionModule): """This module detects whether control flow decisions are made based on the transaction origin.""" name = "Control flow depends on tx.origin" swc_id = TX_ORIGIN_USAGE description = "Check whether control flow decisions are influenced by tx.origin" entry_point = EntryPoint.CALLBACK pre_hooks = ["JUMPI"] post_hooks = ["ORIGIN"] def _execute(self, state: GlobalState) -> List[Issue]: """ :param state: :return: """ return self._analyze_state(state) def _analyze_state(self, state: GlobalState) -> List[Issue]: """ :param state: :return: """ issues = [] if state.get_current_instruction()["opcode"] == "JUMPI": # We're in JUMPI prehook for annotation in state.mstate.stack[-2].annotations: if isinstance(annotation, TxOriginAnnotation): constraints = copy(state.world_state.constraints) try: transaction_sequence = solver.get_transaction_sequence( state, constraints ) except UnsatError: continue description = ( "The tx.origin environment variable has been found to influence a control flow decision. " "Note that using tx.origin as a security control might cause a situation where a user " "inadvertently authorizes a smart contract to perform an action on their behalf. It is " "recommended to use msg.sender instead." ) severity = "Low" """ Note: We report the location of the JUMPI instruction. Usually this maps to an if or require statement. """ issue = Issue( contract=state.environment.active_account.contract_name, function_name=state.environment.active_function_name, address=state.get_current_instruction()["address"], swc_id=TX_ORIGIN_USAGE, bytecode=state.environment.code.bytecode, title="Dependence on tx.origin", severity=severity, description_head="Use of tx.origin as a part of authorization control.", description_tail=description, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), transaction_sequence=transaction_sequence, ) state.annotate( IssueAnnotation( conditions=[And(*constraints)], issue=issue, detector=self ) ) issues.append(issue) else: # In ORIGIN posthook state.mstate.stack[-1].annotate(TxOriginAnnotation()) return issues
detector = TxOrigin()