detectors: Add assembly detector.

Detect functions using inline assembly.

Refs: https://github.com/trailofbits/slither/issues/26
pull/34/head
Cryptomental 6 years ago committed by Josselin
parent 265a7d6a17
commit 1d6cebd991
  1. 9
      scripts/travis_test.sh
  2. 4
      slither/__main__.py
  3. 59
      slither/detectors/statements/assembly.py
  4. 22
      tests/inline_assembly_contract.sol
  5. 49
      tests/inline_assembly_library.sol

@ -53,6 +53,15 @@ if [ $? -ne 2 ]; then
exit 1
fi
slither tests/inline_assembly_contract.sol --disable-solc-warnings
if [ $? -ne 2 ]; then
exit 1
fi
slither tests/inline_assembly_library.sol --disable-solc-warnings
if [ $? -ne 3 ]; then
exit 1
fi
### Test scripts

@ -100,6 +100,7 @@ def main():
from slither.detectors.variables.uninitialized_storage_variables import UninitializedStorageVars
from slither.detectors.variables.unused_state_variables import UnusedStateVars
from slither.detectors.statements.tx_origin import TxOrigin
from slither.detectors.statements.assembly import Assembly
detectors = [Backdoor,
UninitializedStateVarsDetection,
@ -111,7 +112,8 @@ def main():
ArbitrarySend,
Suicidal,
UnusedStateVars,
TxOrigin]
TxOrigin,
Assembly]
from slither.printers.summary.summary import PrinterSummary
from slither.printers.summary.quick_summary import PrinterQuickSummary

@ -0,0 +1,59 @@
"""
Module detecting usage of inline assembly
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.cfg.node import NodeType
class Assembly(AbstractDetector):
"""
Detect usage of inline assembly
"""
ARGUMENT = 'assembly'
HELP = 'assembly usage'
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.HIGH
@staticmethod
def _contains_inline_assembly_use(node):
"""
Check if the node contains ASSEMBLY type
Returns:
(bool)
"""
return node.type == NodeType.ASSEMBLY
def detect_assembly(self, contract):
ret = []
for f in contract.functions:
nodes = f.nodes
assembly_nodes = [n for n in nodes if
self._contains_inline_assembly_use(n)]
if assembly_nodes:
ret.append((f, assembly_nodes))
return ret
def detect(self):
""" Detect the functions that use inline assembly
"""
results = []
for c in self.contracts:
values = self.detect_assembly(c)
for func, nodes in values:
func_name = func.name
info = "Assembly in %s, Contract: %s, Function: %s" % (self.filename,
c.name,
func_name)
self.log(info)
sourceMapping = [n.source_mapping for n in nodes]
results.append({'vuln': 'Assembly',
'sourceMapping': sourceMapping,
'filename': self.filename,
'contract': c.name,
'function_name': func_name})
return results

@ -0,0 +1,22 @@
pragma solidity ^0.4.0;
// taken from https://solidity.readthedocs.io/en/v0.4.25/assembly.html
library GetCode {
function at(address _addr) public view returns (bytes o_code) {
assembly {
// retrieve the size of the code, this needs assembly
let size := extcodesize(_addr)
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
o_code := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(o_code, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(o_code, 0x20), 0, size)
}
}
}

@ -0,0 +1,49 @@
pragma solidity ^0.4.16;
// taken from https://solidity.readthedocs.io/en/v0.4.25/assembly.html
library VectorSum {
// This function is less efficient because the optimizer currently fails to
// remove the bounds checks in array access.
function sumSolidity(uint[] _data) public view returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i)
o_sum += _data[i];
}
// We know that we only access the array in bounds, so we can avoid the check.
// 0x20 needs to be added to an array because the first slot contains the
// array length.
function sumAsm(uint[] _data) public view returns (uint o_sum) {
for (uint i = 0; i < _data.length; ++i) {
assembly {
o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
}
}
}
// Same as above, but accomplish the entire code within inline assembly.
function sumPureAsm(uint[] _data) public view returns (uint o_sum) {
assembly {
// Load the length (first 32 bytes)
let len := mload(_data)
// Skip over the length field.
//
// Keep temporary variable so it can be incremented in place.
//
// NOTE: incrementing _data would result in an unusable
// _data variable after this assembly block
let data := add(_data, 0x20)
// Iterate until the bound is not met.
for
{ let end := add(data, len) }
lt(data, end)
{ data := add(data, 0x20) }
{
o_sum := add(o_sum, mload(data))
}
}
}
}
Loading…
Cancel
Save