Update the cross function reentrancy heuristic to work on variable read, and public state variables

pull/1351/head
Josselin Feist 2 years ago
parent 303ed83736
commit d2a93f0225
  1. 33
      slither/core/declarations/contract.py
  2. 24
      slither/detectors/reentrancy/reentrancy_eth.py
  3. 24
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  4. 45
      tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol
  5. 677
      tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol.0.8.10.ReentrancyEth.json

@ -2,8 +2,9 @@
Contract module
"""
import logging
from collections import defaultdict
from pathlib import Path
from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union
from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union, Set
from crytic_compile.platform import Type as PlatformType
@ -101,7 +102,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
self.file_scope: "FileScope" = scope
# memoize
self._state_variables_written_in_reentrant_targets: Optional[List["StateVariable"]] = None
self._state_variables_used_in_reentrant_targets: Optional[Dict["StateVariable", Set[Union["StateVariable", "Function"]]]]= None
###################################################################################
###################################################################################
@ -353,14 +354,26 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
return list(set(slithir_variables))
@property
def state_variables_written_in_reentrant_targets(self) -> List["StateVariable"]:
if self._state_variables_written_in_reentrant_targets is None:
reentrant_functions = [f for f in self.functions if f.is_reentrant]
variables_writtenss = [f.all_state_variables_written() for f in reentrant_functions]
self._state_variables_written_in_reentrant_targets = [
item for sublist in variables_writtenss for item in sublist
]
return self._state_variables_written_in_reentrant_targets
def state_variables_used_in_reentrant_targets(self) -> Dict["StateVariable", Set[Union["StateVariable", "Function"]]]:
"""
Returns the state variables used in reentrant targets. Heuristics:
- Variable used (read/write) in entry points that are reentrant
- State variables that are public
"""
from slither.core.variables.state_variable import StateVariable
if self._state_variables_used_in_reentrant_targets is None:
reentrant_functions = [f for f in self.functions_entry_points if f.is_reentrant]
variables_used: Dict[StateVariable, Set[Union[StateVariable, "Function"]]] = defaultdict(set)
for function in reentrant_functions:
for ir in function.all_slithir_operations():
state_variables = [v for v in ir.used if isinstance(v, StateVariable)]
for state_variable in state_variables:
variables_used[state_variable].add(ir.function)
for variable in [v for v in self.state_variables if v.visibility == "public"]:
variables_used[variable].add(variable)
self._state_variables_used_in_reentrant_targets = variables_used
return self._state_variables_used_in_reentrant_targets
# endregion
###################################################################################

@ -5,13 +5,14 @@
Iterate over all the nodes of the graph until reaching a fixpoint
"""
from collections import namedtuple, defaultdict
from typing import List
from typing import List, Dict, Set
from slither.detectors.abstract_detector import DetectorClassification
from .reentrancy import Reentrancy, to_hashable
from ...utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes", "cross_functions"])
class ReentrancyEth(Reentrancy):
@ -52,9 +53,10 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
STANDARD_JSON = False
def find_reentrancies(self):
result = defaultdict(set)
def find_reentrancies(self) -> Dict[FindingKey, Set[FindingValue]]:
result: Dict[FindingKey, Set[FindingValue]] = defaultdict(set)
for contract in self.contracts: # pylint: disable=too-many-nested-blocks
variables_used_in_reentrancy = contract.state_variables_used_in_reentrant_targets
for f in contract.functions_and_modifiers_declared:
for node in f.nodes:
# dead code
@ -72,12 +74,13 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
tuple(variables_used_in_reentrancy[v])
)
for (v, nodes) in node.context[self.KEY].written.items()
if v in node.context[self.KEY].reads_prior_calls[c]
and (
f.is_reentrant
or v in contract.state_variables_written_in_reentrant_targets
or v in variables_used_in_reentrancy
)
}
@ -92,7 +95,7 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
result[finding_key] |= set(read_then_written)
return result
def _detect(self): # pylint: disable=too-many-branches
def _detect(self) -> List[Output]: # pylint: disable=too-many-branches,too-many-locals
""""""
super()._detect()
@ -102,10 +105,11 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
result_sorted = sorted(list(reentrancies.items()), key=lambda x: x[0].function.name)
varsWritten: List[FindingValue]
for (func, calls, send_eth), varsWritten in result_sorted:
varsWrittenSet: Set[FindingValue]
for (func, calls, send_eth), varsWrittenSet in result_sorted:
calls = sorted(list(set(calls)), key=lambda x: x[0].node_id)
send_eth = sorted(list(set(send_eth)), key=lambda x: x[0].node_id)
varsWritten = sorted(varsWritten, key=lambda x: (x.variable.name, x.node.node_id))
varsWritten = sorted(varsWrittenSet, key=lambda x: (x.variable.name, x.node.node_id))
info = ["Reentrancy in ", func, ":\n"]
info += ["\tExternal calls:\n"]
@ -127,6 +131,10 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
for other_node in finding_value.nodes:
if other_node != finding_value.node:
info += ["\t\t- ", other_node, "\n"]
if finding_value.cross_functions:
info += ["\t", finding_value.variable," can be used in cross function reentrancies:\n"]
for cross in finding_value.cross_functions:
info += ["\t- ", cross, "\n"]
# Create our JSON result
res = self.generate_result(info)

@ -5,12 +5,14 @@
Iterate over all the nodes of the graph until reaching a fixpoint
"""
from collections import namedtuple, defaultdict
from typing import Dict, Set, List
from slither.detectors.abstract_detector import DetectorClassification
from .reentrancy import Reentrancy, to_hashable
from ...utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes", "cross_functions"])
class ReentrancyReadBeforeWritten(Reentrancy):
@ -49,9 +51,10 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
STANDARD_JSON = False
def find_reentrancies(self):
result = defaultdict(set)
def find_reentrancies(self) -> Dict[FindingKey, Set[FindingValue]]:
result: Dict[FindingKey, Set[FindingValue]] = defaultdict(set)
for contract in self.contracts: # pylint: disable=too-many-nested-blocks
variables_used_in_reentrancy = contract.state_variables_used_in_reentrant_targets
for f in contract.functions_and_modifiers_declared:
for node in f.nodes:
# dead code
@ -67,12 +70,13 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
tuple(variables_used_in_reentrancy[v])
)
for (v, nodes) in node.context[self.KEY].written.items()
if v in node.context[self.KEY].reads_prior_calls[c]
and (
f.is_reentrant
or v in contract.state_variables_written_in_reentrant_targets
or v in variables_used_in_reentrancy
)
}
@ -86,7 +90,7 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
result[finding_key] |= read_then_written
return result
def _detect(self): # pylint: disable=too-many-branches
def _detect(self) -> List[Output]: # pylint: disable=too-many-branches
""""""
super()._detect()
@ -95,9 +99,11 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
results = []
result_sorted = sorted(list(reentrancies.items()), key=lambda x: x[0].function.name)
for (func, calls), varsWritten in result_sorted:
varsWritten: List[FindingValue]
varsWrittenSet: Set[FindingValue]
for (func, calls), varsWrittenSet in result_sorted:
calls = sorted(list(set(calls)), key=lambda x: x[0].node_id)
varsWritten = sorted(varsWritten, key=lambda x: (x.variable.name, x.node.node_id))
varsWritten = sorted(varsWrittenSet, key=lambda x: (x.variable.name, x.node.node_id))
info = ["Reentrancy in ", func, ":\n"]
@ -113,6 +119,10 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
for other_node in finding_value.nodes:
if other_node != finding_value.node:
info += ["\t\t- ", other_node, "\n"]
if finding_value.cross_functions:
info += ["\t", finding_value.variable," can be used in cross function reentrancies:\n"]
for cross in finding_value.cross_functions:
info += ["\t- ", cross, "\n"]
# Create our JSON result
res = self.generate_result(info)

@ -105,4 +105,47 @@ contract TestWithoutBugInternal{
Receiver(msg.sender).send_funds{value: amount}();
}
}
}
contract TestBugWithPublicVariable{
mapping(address => uint) public balances;
modifier nonReentrant(){
_;
}
function withdraw(uint amount) nonReentrant public{
withdraw_internal(amount);
}
function withdraw_internal(uint amount) internal{
require(amount <= balances[msg.sender]);
Receiver(msg.sender).send_funds{value: amount}();
balances[msg.sender] -= amount;
}
}
contract TestWithBugNonReentrantRead{
mapping(address => uint) balances;
modifier nonReentrant(){
_;
}
function withdraw(uint amount) nonReentrant public{
require(amount <= balances[msg.sender]);
Receiver(msg.sender).send_funds{value: amount}();
balances[msg.sender] -= amount;
}
// Simulate a reentrancy that allows to read variable in a potential incorrect state during a reentrancy
// This is more likely to impact protocol like reentrancy
function read() public returns(uint){
uint amount = balances[msg.sender];
return amount;
}
}

@ -6,18 +6,18 @@
"type": "function",
"name": "withdraw",
"source_mapping": {
"start": 181,
"start": 3089,
"length": 207,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
13,
14,
15,
16,
17
138,
139,
140,
141,
142
],
"starting_column": 5,
"ending_column": 6
@ -25,36 +25,37 @@
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestWithBug",
"name": "TestWithBugNonReentrantRead",
"source_mapping": {
"start": 67,
"length": 506,
"start": 2959,
"length": 629,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
130,
131,
132,
133,
134,
135,
136,
137,
138,
139,
140,
141,
142,
143,
144,
145,
146,
147,
148,
149,
150,
151
],
"starting_column": 1,
"ending_column": 2
@ -67,14 +68,14 @@
"type": "node",
"name": "Receiver(msg.sender).send_funds{value: amount}()",
"source_mapping": {
"start": 292,
"start": 3200,
"length": 48,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
15
140
],
"starting_column": 10,
"ending_column": 58
@ -84,18 +85,18 @@
"type": "function",
"name": "withdraw",
"source_mapping": {
"start": 181,
"start": 3089,
"length": 207,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
13,
14,
15,
16,
17
138,
139,
140,
141,
142
],
"starting_column": 5,
"ending_column": 6
@ -103,36 +104,37 @@
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestWithBug",
"name": "TestWithBugNonReentrantRead",
"source_mapping": {
"start": 67,
"length": 506,
"start": 2959,
"length": 629,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
130,
131,
132,
133,
134,
135,
136,
137,
138,
139,
140,
141,
142,
143,
144,
145,
146,
147,
148,
149,
150,
151
],
"starting_column": 1,
"ending_column": 2
@ -150,14 +152,14 @@
"type": "node",
"name": "balances[msg.sender] -= amount",
"source_mapping": {
"start": 351,
"start": 3259,
"length": 30,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
16
141
],
"starting_column": 10,
"ending_column": 40
@ -167,18 +169,18 @@
"type": "function",
"name": "withdraw",
"source_mapping": {
"start": 181,
"start": 3089,
"length": 207,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
13,
14,
15,
16,
17
138,
139,
140,
141,
142
],
"starting_column": 5,
"ending_column": 6
@ -186,36 +188,37 @@
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestWithBug",
"name": "TestWithBugNonReentrantRead",
"source_mapping": {
"start": 67,
"length": 506,
"start": 2959,
"length": 629,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
130,
131,
132,
133,
134,
135,
136,
137,
138,
139,
140,
141,
142,
143,
144,
145,
146,
147,
148,
149,
150,
151
],
"starting_column": 1,
"ending_column": 2
@ -231,10 +234,10 @@
}
}
],
"description": "Reentrancy in TestWithBug.withdraw(uint256) (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#13-17):\n\tExternal calls:\n\t- Receiver(msg.sender).send_funds{value: amount}() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#15)\n\tState variables written after the call(s):\n\t- balances[msg.sender] -= amount (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#16)\n",
"markdown": "Reentrancy in [TestWithBug.withdraw(uint256)](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L13-L17):\n\tExternal calls:\n\t- [Receiver(msg.sender).send_funds{value: amount}()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L15)\n\tState variables written after the call(s):\n\t- [balances[msg.sender] -= amount](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L16)\n",
"first_markdown_element": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L13-L17",
"id": "746b848eb5d1102128ce24fa085ea13e78073daa2e2934383a204dfdcf8f02c0",
"description": "Reentrancy in TestWithBugNonReentrantRead.withdraw(uint256) (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#138-142):\n\tExternal calls:\n\t- Receiver(msg.sender).send_funds{value: amount}() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#140)\n\tState variables written after the call(s):\n\t- balances[msg.sender] -= amount (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#141)\n\tTestWithBugNonReentrantRead.balances (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#132) can be used in cross function reentrancies:\n\t- TestWithBugNonReentrantRead.read() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#146-149)\n",
"markdown": "Reentrancy in [TestWithBugNonReentrantRead.withdraw(uint256)](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L138-L142):\n\tExternal calls:\n\t- [Receiver(msg.sender).send_funds{value: amount}()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L140)\n\tState variables written after the call(s):\n\t- [balances[msg.sender] -= amount](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L141)\n\t[TestWithBugNonReentrantRead.balances](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L132) can be used in cross function reentrancies:\n\t- [TestWithBugNonReentrantRead.read()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L146-L149)\n",
"first_markdown_element": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L138-L142",
"id": "0b2149d8ea8554c24092bad5ce3061d661d4f0447d5d96716893538474bca40f",
"check": "reentrancy-eth",
"impact": "High",
"confidence": "Medium"
@ -494,10 +497,482 @@
}
}
],
"description": "Reentrancy in TestWithBugInternal.withdraw_internal(uint256) (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#62-66):\n\tExternal calls:\n\t- Receiver(msg.sender).send_funds{value: amount}() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#64)\n\tState variables written after the call(s):\n\t- balances[msg.sender] -= amount (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#65)\n",
"markdown": "Reentrancy in [TestWithBugInternal.withdraw_internal(uint256)](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L62-L66):\n\tExternal calls:\n\t- [Receiver(msg.sender).send_funds{value: amount}()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L64)\n\tState variables written after the call(s):\n\t- [balances[msg.sender] -= amount](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L65)\n",
"description": "Reentrancy in TestWithBugInternal.withdraw_internal(uint256) (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#62-66):\n\tExternal calls:\n\t- Receiver(msg.sender).send_funds{value: amount}() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#64)\n\tState variables written after the call(s):\n\t- balances[msg.sender] -= amount (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#65)\n\tTestWithBugInternal.balances (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#52) can be used in cross function reentrancies:\n\t- TestWithBugInternal.withdraw_all_internal() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#72-76)\n",
"markdown": "Reentrancy in [TestWithBugInternal.withdraw_internal(uint256)](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L62-L66):\n\tExternal calls:\n\t- [Receiver(msg.sender).send_funds{value: amount}()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L64)\n\tState variables written after the call(s):\n\t- [balances[msg.sender] -= amount](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L65)\n\t[TestWithBugInternal.balances](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L52) can be used in cross function reentrancies:\n\t- [TestWithBugInternal.withdraw_all_internal()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L72-L76)\n",
"first_markdown_element": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L62-L66",
"id": "d0680f2465dbe3b98cba27b175607d789949a9d1a1b686bd373b584caf3a0913",
"id": "7d618f027540d61d9af79a3a9475677476d1c4d7ad1be68ff8026f6c0d4cdc82",
"check": "reentrancy-eth",
"impact": "High",
"confidence": "Medium"
},
{
"elements": [
{
"type": "function",
"name": "withdraw_internal",
"source_mapping": {
"start": 2749,
"length": 205,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
122,
123,
124,
125,
126
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestBugWithPublicVariable",
"source_mapping": {
"start": 2516,
"length": 441,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
123,
124,
125,
126,
127,
128
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "withdraw_internal(uint256)"
}
},
{
"type": "node",
"name": "Receiver(msg.sender).send_funds{value: amount}()",
"source_mapping": {
"start": 2858,
"length": 48,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
124
],
"starting_column": 10,
"ending_column": 58
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "withdraw_internal",
"source_mapping": {
"start": 2749,
"length": 205,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
122,
123,
124,
125,
126
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestBugWithPublicVariable",
"source_mapping": {
"start": 2516,
"length": 441,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
123,
124,
125,
126,
127,
128
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "withdraw_internal(uint256)"
}
}
},
"additional_fields": {
"underlying_type": "external_calls"
}
},
{
"type": "node",
"name": "balances[msg.sender] -= amount",
"source_mapping": {
"start": 2917,
"length": 30,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
125
],
"starting_column": 10,
"ending_column": 40
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "withdraw_internal",
"source_mapping": {
"start": 2749,
"length": 205,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
122,
123,
124,
125,
126
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestBugWithPublicVariable",
"source_mapping": {
"start": 2516,
"length": 441,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
123,
124,
125,
126,
127,
128
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "withdraw_internal(uint256)"
}
}
},
"additional_fields": {
"underlying_type": "variables_written",
"variable_name": "balances"
}
}
],
"description": "Reentrancy in TestBugWithPublicVariable.withdraw_internal(uint256) (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#122-126):\n\tExternal calls:\n\t- Receiver(msg.sender).send_funds{value: amount}() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#124)\n\tState variables written after the call(s):\n\t- balances[msg.sender] -= amount (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#125)\n\tTestBugWithPublicVariable.balances (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#112) can be used in cross function reentrancies:\n\t- TestBugWithPublicVariable.balances (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#112)\n",
"markdown": "Reentrancy in [TestBugWithPublicVariable.withdraw_internal(uint256)](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L122-L126):\n\tExternal calls:\n\t- [Receiver(msg.sender).send_funds{value: amount}()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L124)\n\tState variables written after the call(s):\n\t- [balances[msg.sender] -= amount](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L125)\n\t[TestBugWithPublicVariable.balances](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L112) can be used in cross function reentrancies:\n\t- [TestBugWithPublicVariable.balances](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L112)\n",
"first_markdown_element": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L122-L126",
"id": "a3e52c882aa9fb88119aa3507f4158436bfe3f1abee0828665afa41213587097",
"check": "reentrancy-eth",
"impact": "High",
"confidence": "Medium"
},
{
"elements": [
{
"type": "function",
"name": "withdraw",
"source_mapping": {
"start": 181,
"length": 207,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
13,
14,
15,
16,
17
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestWithBug",
"source_mapping": {
"start": 67,
"length": 506,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "withdraw(uint256)"
}
},
{
"type": "node",
"name": "Receiver(msg.sender).send_funds{value: amount}()",
"source_mapping": {
"start": 292,
"length": 48,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
15
],
"starting_column": 10,
"ending_column": 58
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "withdraw",
"source_mapping": {
"start": 181,
"length": 207,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
13,
14,
15,
16,
17
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestWithBug",
"source_mapping": {
"start": 67,
"length": 506,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "withdraw(uint256)"
}
}
},
"additional_fields": {
"underlying_type": "external_calls"
}
},
{
"type": "node",
"name": "balances[msg.sender] -= amount",
"source_mapping": {
"start": 351,
"length": 30,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
16
],
"starting_column": 10,
"ending_column": 40
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "withdraw",
"source_mapping": {
"start": 181,
"length": 207,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
13,
14,
15,
16,
17
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "TestWithBug",
"source_mapping": {
"start": 67,
"length": 506,
"filename_relative": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol",
"is_dependency": false,
"lines": [
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "withdraw(uint256)"
}
}
},
"additional_fields": {
"underlying_type": "variables_written",
"variable_name": "balances"
}
}
],
"description": "Reentrancy in TestWithBug.withdraw(uint256) (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#13-17):\n\tExternal calls:\n\t- Receiver(msg.sender).send_funds{value: amount}() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#15)\n\tState variables written after the call(s):\n\t- balances[msg.sender] -= amount (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#16)\n\tTestWithBug.balances (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#7) can be used in cross function reentrancies:\n\t- TestWithBug.withdraw_all() (tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#19-23)\n",
"markdown": "Reentrancy in [TestWithBug.withdraw(uint256)](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L13-L17):\n\tExternal calls:\n\t- [Receiver(msg.sender).send_funds{value: amount}()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L15)\n\tState variables written after the call(s):\n\t- [balances[msg.sender] -= amount](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L16)\n\t[TestWithBug.balances](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L7) can be used in cross function reentrancies:\n\t- [TestWithBug.withdraw_all()](tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L19-L23)\n",
"first_markdown_element": "tests/detectors/reentrancy-eth/0.8.10/reentrancy_with_non_reentrant.sol#L13-L17",
"id": "bcfa65e776908d618f202fa48f03dde3fbf8397b752d2e8cc3c8e46019e9e174",
"check": "reentrancy-eth",
"impact": "High",
"confidence": "Medium"

Loading…
Cancel
Save