mirror of https://github.com/crytic/slither
parent
f7ab4a734f
commit
4d1d32b63f
@ -0,0 +1,93 @@ |
||||
""" |
||||
Module detecting incorrect operator usage for exponentiation where bitwise xor '^' is used instead of '**' |
||||
""" |
||||
from typing import Tuple, List, Union |
||||
|
||||
from slither.core.cfg.node import Node |
||||
from slither.core.declarations import Contract, Function |
||||
from slither.detectors.abstract_detector import ( |
||||
AbstractDetector, |
||||
DetectorClassification, |
||||
DETECTOR_INFO, |
||||
) |
||||
from slither.slithir.operations import Binary, BinaryType, Operation |
||||
from slither.slithir.utils.utils import RVALUE |
||||
from slither.slithir.variables.constant import Constant |
||||
from slither.utils.output import Output |
||||
|
||||
|
||||
def _is_constant_candidate(var: Union[RVALUE, Function]) -> bool: |
||||
""" |
||||
Check if the variable is a constant. |
||||
Do not consider variable that are expressed with hexadecimal. |
||||
Something like 2^0xf is likely to be a correct bitwise operator |
||||
:param var: |
||||
:return: |
||||
""" |
||||
return isinstance(var, Constant) and not var.original_value.startswith("0x") |
||||
|
||||
|
||||
def _is_bitwise_xor_on_constant(ir: Operation) -> bool: |
||||
return ( |
||||
isinstance(ir, Binary) |
||||
and ir.type == BinaryType.CARET |
||||
and (_is_constant_candidate(ir.variable_left) or _is_constant_candidate(ir.variable_right)) |
||||
) |
||||
|
||||
|
||||
def _detect_incorrect_operator(contract: Contract) -> List[Tuple[Function, Node]]: |
||||
ret: List[Tuple[Function, Node]] = [] |
||||
f: Function |
||||
for f in contract.functions + contract.modifiers: # type:ignore |
||||
# Heuristic: look for binary expressions with ^ operator where at least one of the operands is a constant, and |
||||
# the constant is not in hex, because hex typically is used with bitwise xor and not exponentiation |
||||
nodes = [node for node in f.nodes for ir in node.irs if _is_bitwise_xor_on_constant(ir)] |
||||
for node in nodes: |
||||
ret.append((f, node)) |
||||
return ret |
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods |
||||
class IncorrectOperatorExponentiation(AbstractDetector): |
||||
""" |
||||
Incorrect operator usage of bitwise xor mistaking it for exponentiation |
||||
""" |
||||
|
||||
ARGUMENT = "incorrect-exp" |
||||
HELP = "Incorrect exponentiation" |
||||
IMPACT = DetectorClassification.HIGH |
||||
CONFIDENCE = DetectorClassification.MEDIUM |
||||
|
||||
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-exponentiation" |
||||
|
||||
WIKI_TITLE = "Incorrect exponentiation" |
||||
WIKI_DESCRIPTION = "Detect use of bitwise `xor ^` instead of exponential `**`" |
||||
WIKI_EXPLOIT_SCENARIO = """ |
||||
```solidity |
||||
contract Bug{ |
||||
uint UINT_MAX = 2^256 - 1; |
||||
... |
||||
} |
||||
``` |
||||
Alice deploys a contract in which `UINT_MAX` incorrectly uses `^` operator instead of `**` for exponentiation""" |
||||
|
||||
WIKI_RECOMMENDATION = "Use the correct operator `**` for exponentiation." |
||||
|
||||
def _detect(self) -> List[Output]: |
||||
"""Detect the incorrect operator usage for exponentiation where bitwise xor ^ is used instead of ** |
||||
|
||||
Returns: |
||||
list: (function, node) |
||||
""" |
||||
results: List[Output] = [] |
||||
for c in self.compilation_unit.contracts_derived: |
||||
res = _detect_incorrect_operator(c) |
||||
for (func, node) in res: |
||||
info: DETECTOR_INFO = [ |
||||
func, |
||||
" has bitwise-xor operator ^ instead of the exponentiation operator **: \n", |
||||
] |
||||
info += ["\t - ", node, "\n"] |
||||
results.append(self.generate_result(info)) |
||||
|
||||
return results |
@ -0,0 +1,69 @@ |
||||
from typing import List |
||||
from slither.detectors.abstract_detector import ( |
||||
AbstractDetector, |
||||
DetectorClassification, |
||||
DETECTOR_INFO, |
||||
) |
||||
from slither.slithir.operations import ( |
||||
Binary, |
||||
BinaryType, |
||||
) |
||||
|
||||
from slither.core.declarations import Function |
||||
from slither.utils.output import Output |
||||
|
||||
|
||||
class TautologicalCompare(AbstractDetector): |
||||
""" |
||||
Same variable comparison detector |
||||
""" |
||||
|
||||
ARGUMENT = "tautological-compare" |
||||
HELP = "Comparing a variable to itself always returns true or false, depending on comparison" |
||||
IMPACT = DetectorClassification.MEDIUM |
||||
CONFIDENCE = DetectorClassification.HIGH |
||||
|
||||
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#tautological-compare" |
||||
|
||||
WIKI_TITLE = "Tautological compare" |
||||
WIKI_DESCRIPTION = "A variable compared to itself is probably an error as it will always return `true` for `==`, `>=`, `<=` and always `false` for `<`, `>` and `!=`." |
||||
WIKI_EXPLOIT_SCENARIO = """ |
||||
```solidity |
||||
function check(uint a) external returns(bool){ |
||||
return (a >= a); |
||||
} |
||||
``` |
||||
`check` always return true.""" |
||||
|
||||
WIKI_RECOMMENDATION = "Remove comparison or compare to different value." |
||||
|
||||
def _check_function(self, f: Function) -> List[Output]: |
||||
affected_nodes = set() |
||||
for node in f.nodes: |
||||
for ir in node.irs: |
||||
if isinstance(ir, Binary): |
||||
if ir.type in [ |
||||
BinaryType.GREATER, |
||||
BinaryType.GREATER_EQUAL, |
||||
BinaryType.LESS, |
||||
BinaryType.LESS_EQUAL, |
||||
BinaryType.EQUAL, |
||||
BinaryType.NOT_EQUAL, |
||||
]: |
||||
if ir.variable_left == ir.variable_right: |
||||
affected_nodes.add(node) |
||||
|
||||
results = [] |
||||
for n in affected_nodes: |
||||
info: DETECTOR_INFO = [f, " compares a variable to itself:\n\t", n, "\n"] |
||||
res = self.generate_result(info) |
||||
results.append(res) |
||||
return results |
||||
|
||||
def _detect(self): |
||||
results = [] |
||||
|
||||
for f in self.compilation_unit.functions_and_modifiers: |
||||
results.extend(self._check_function(f)) |
||||
|
||||
return results |
@ -0,0 +1,6 @@ |
||||
|
||||
contract A{ |
||||
function check(uint a) external returns(bool){ |
||||
return (a >= a); |
||||
} |
||||
} |
Binary file not shown.
Loading…
Reference in new issue