mirror of https://github.com/ConsenSys/mythril
parent
aaa8e132db
commit
a4118e14b8
@ -1,137 +0,0 @@ |
||||
"""This module contains the detection code SWC-128 - DOS with block gas limit.""" |
||||
|
||||
import logging |
||||
from typing import Dict, cast, List |
||||
|
||||
from mythril.analysis.swc_data import DOS_WITH_BLOCK_GAS_LIMIT |
||||
from mythril.analysis.report import Issue |
||||
from mythril.analysis.modules.base import DetectionModule |
||||
from mythril.analysis.solver import get_transaction_sequence, UnsatError |
||||
from mythril.analysis.analysis_args import analysis_args |
||||
from mythril.laser.ethereum.state.global_state import GlobalState |
||||
from mythril.laser.ethereum.state.annotation import StateAnnotation |
||||
from mythril.laser.ethereum import util |
||||
from copy import copy |
||||
|
||||
log = logging.getLogger(__name__) |
||||
|
||||
|
||||
class VisitsAnnotation(StateAnnotation): |
||||
"""State annotation that stores the addresses of state-modifying operations""" |
||||
|
||||
def __init__(self) -> None: |
||||
self.loop_start = None # type: int |
||||
self.jump_targets = {} # type: Dict[int, int] |
||||
|
||||
def __copy__(self): |
||||
result = VisitsAnnotation() |
||||
|
||||
result.loop_start = self.loop_start |
||||
result.jump_targets = copy(self.jump_targets) |
||||
return result |
||||
|
||||
|
||||
class DosModule(DetectionModule): |
||||
"""This module consists of a makeshift loop detector that annotates the state with |
||||
a list of byte ranges likely to be loops. If a CALL or SSTORE detection is found in |
||||
one of the ranges it creates a low-severity issue. This is not super precise but |
||||
good enough to identify places that warrant a closer look. Checking the loop condition |
||||
would be a possible improvement. |
||||
""" |
||||
|
||||
def __init__(self) -> None: |
||||
"""""" |
||||
super().__init__( |
||||
name="DOS", |
||||
swc_id=DOS_WITH_BLOCK_GAS_LIMIT, |
||||
description="Check for DOS", |
||||
entrypoint="callback", |
||||
pre_hooks=["JUMP", "JUMPI", "CALL", "SSTORE"], |
||||
) |
||||
|
||||
def _execute(self, state: GlobalState) -> None: |
||||
|
||||
""" |
||||
:param state: |
||||
:return: |
||||
""" |
||||
issues = self._analyze_state(state) |
||||
self.issues.extend(issues) |
||||
|
||||
def _analyze_state(self, state: GlobalState) -> List[Issue]: |
||||
""" |
||||
:param state: the current state |
||||
:return: returns the issues for that corresponding state |
||||
""" |
||||
|
||||
opcode = state.get_current_instruction()["opcode"] |
||||
address = state.get_current_instruction()["address"] |
||||
|
||||
annotations = cast( |
||||
List[VisitsAnnotation], list(state.get_annotations(VisitsAnnotation)) |
||||
) |
||||
|
||||
if len(annotations) == 0: |
||||
annotation = VisitsAnnotation() |
||||
state.annotate(annotation) |
||||
else: |
||||
annotation = annotations[0] |
||||
|
||||
if opcode in ["JUMP", "JUMPI"]: |
||||
|
||||
if annotation.loop_start is not None: |
||||
return [] |
||||
try: |
||||
target = util.get_concrete_int(state.mstate.stack[-1]) |
||||
except TypeError: |
||||
log.debug("Symbolic target encountered in dos module") |
||||
return [] |
||||
if target in annotation.jump_targets: |
||||
annotation.jump_targets[target] += 1 |
||||
else: |
||||
annotation.jump_targets[target] = 1 |
||||
|
||||
if annotation.jump_targets[target] > min(2, analysis_args.loop_bound - 1): |
||||
annotation.loop_start = address |
||||
|
||||
elif annotation.loop_start is not None: |
||||
|
||||
if opcode == "CALL": |
||||
operation = "A message call" |
||||
else: |
||||
operation = "A storage modification" |
||||
|
||||
description_head = ( |
||||
"Potential denial-of-service if block gas limit is reached." |
||||
) |
||||
description_tail = "{} is executed in a loop. Be aware that the transaction may fail to execute if the loop is unbounded and the necessary gas exceeds the block gas limit.".format( |
||||
operation |
||||
) |
||||
|
||||
try: |
||||
transaction_sequence = get_transaction_sequence( |
||||
state, state.mstate.constraints |
||||
) |
||||
except UnsatError: |
||||
return [] |
||||
|
||||
issue = Issue( |
||||
contract=state.environment.active_account.contract_name, |
||||
function_name=state.environment.active_function_name, |
||||
address=annotation.loop_start, |
||||
swc_id=DOS_WITH_BLOCK_GAS_LIMIT, |
||||
bytecode=state.environment.code.bytecode, |
||||
title="Potential denial-of-service if block gas limit is reached", |
||||
severity="Low", |
||||
description_head=description_head, |
||||
description_tail=description_tail, |
||||
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), |
||||
transaction_sequence=transaction_sequence, |
||||
) |
||||
|
||||
return [issue] |
||||
|
||||
return [] |
||||
|
||||
|
||||
detector = DosModule() |
Loading…
Reference in new issue