From 539e04972ae509765051930276b688f2f3a904f1 Mon Sep 17 00:00:00 2001 From: POTHURI HARIKA <cb.en.p2cys21018@cb.students.amrita.edu> Date: Thu, 15 Jun 2023 12:20:28 +0530 Subject: [PATCH] Upload New File --- .../Rules/SOLIDITY_GAS_LIMIT_IN_LOOPS.md | 516 ++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 Tools/SmartCheck/Solidity/Rules/SOLIDITY_GAS_LIMIT_IN_LOOPS.md diff --git a/Tools/SmartCheck/Solidity/Rules/SOLIDITY_GAS_LIMIT_IN_LOOPS.md b/Tools/SmartCheck/Solidity/Rules/SOLIDITY_GAS_LIMIT_IN_LOOPS.md new file mode 100644 index 0000000..7e0a30e --- /dev/null +++ b/Tools/SmartCheck/Solidity/Rules/SOLIDITY_GAS_LIMIT_IN_LOOPS.md @@ -0,0 +1,516 @@ +# Analysis of Smart Contract Security Vulnerabilities and Tools  +     <br/>    <br/> + <br/> + + +## SOLIDITY_GAS_LIMIT_IN_LOOPS +### Rule Description +<p> + Ethereum is a very resource-constrained environment. Prices per computational step are orders of magnitude higher than with centralized providers. Moreover, Ethereum miners impose a limit on the total number of gas consumed in a block. If <code>array.length</code> is large enough, the function exceeds the block gas limit, and transactions calling it will never be confirmed: +</p> +<pre><code> + for (uint256 i = 0; i < array.length ; i++) { + cosltyFunc(); + } +</code></pre> +<p> + This becomes a security issue, if an external actor influences <code>array.length</code>. + E.g., if array enumerates all registered addresses, an adversary can register many addresses, causing the problem described above. +</p> +<p> + Vulnerability type by SmartDec classification: <a href="https://github.com/smartdec/classification#gas-limitations"> + Infinite loops</a>. +</p> + + +### Solidity-Rules + +  + +``` +//forStatement + [ <!-- i = 0; --> + expression[1][text()[1] = "="]/expression[2]//numberLiteral/decimalNumber[text()[1] = "0"] + <!-- uint i = 0; --> + or expression[1]/variableDeclaration[text()[1] = "="]/expression//numberLiteral/decimalNumber[text()[1] = "0"] + <!-- uint i; --> + or expression[1]/variableDeclaration[not(text()[1] = "=")] + ] + [ <!-- ".length" in condition and base is not in memory --> + condition/expression[matches(text()[1], "<|<=")]/expression[2][text()[1] = ".length"]/expression/primaryExpression/identifier + <!-- and array is neither public or external function argument --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text())] + <!-- nor internal or private function argument with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text())] + <!-- nor copied to local variable with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text())] + <!-- may be a variable in condition and it is ... --> + or condition/expression[matches(text()[1], "<|< =")]/expression[2]/primaryExpression/identifier + [ <!-- new variable with non-memory array length --> + text()[1] = (ancestor::functionDefinition//variableDeclaration[text()[1] = "="] + [expression[text()[1] = ".length"]/expression/primaryExpression/identifier + <!-- and array is neither public or external function argument --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text())] + <!-- nor internal or private function argument with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text())] + <!-- nor copied to local variable with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text())] + ]/identifier/text()[1]) + <!-- or reused variable with non-memory array length --> + or text()[1] = (ancestor::functionDefinition//expression[text()[1] = "="] + [expression[2][text()[1] = ".length"]/expression/primaryExpression/identifier + <!-- and array is neither public or external function argument --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text())] + <!-- nor internal or private function argument with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text())] + <!-- nor copied to local variable with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text())] + ]/expression[1]//identifier/text()[1]) + ] + ] +``` + +  + +``` +//forStatement + [ <!-- i = 0; --> + expression[1][text()[1] = "="]/expression[2]//numberLiteral/decimalNumber[text()[1] = "0"] + <!-- uint i = 0; --> + or expression[1]/variableDeclaration[text()[1] = "="]/expression//numberLiteral/decimalNumber[text()[1] = "0"] + <!-- uint i; --> + or expression[1]/variableDeclaration[not(text()[1] = "=")] + ] + [ <!-- ".length" in condition and base is in memory --> + condition/expression[matches(text()[1], "<|<=")]/expression[2][text()[1] = ".length"]/expression/primaryExpression/identifier + [ <!-- and array is either public or external function argument --> + text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text() + <!-- or internal or private function argument with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text() + <!-- or copied to local variable with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text() + ] + <!-- may be a variable in condition and it is ... --> + or condition/expression[matches(text()[1], "<|<=")]/expression[2]/primaryExpression/identifier + [ <!-- new variable with memory array length --> + text()[1] = (ancestor::functionDefinition//variableDeclaration[text()[1] = "="] + [expression[text()[1] = ".length"]/expression/primaryExpression/identifier + [ <!-- and array is either public or external function argument --> + text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text() + <!-- or internal or private function argument with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text() + <!-- or copied to local variable with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text() + ] + ]/identifier/text()[1]) + <!-- or reused variable with memory array length --> + or text()[1] = (ancestor::functionDefinition//expression[text()[1] = "="] + [expression[2][text()[1] = ".length"]/expression/primaryExpression/identifier + [ <!-- and array is either public or external function argument --> + text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text() + <!-- or internal or private function argument with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text() + <!-- or copied to local variable with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text() + ] + ]/expression[1]//identifier/text()[1]) + ] + ] +``` + +  + +``` +forStatement + [ + ( <!-- either reused variable with .length in pre-condition --> + expression[1][text()[1] = "="]/expression[2][text()[1] = ".length"]/expression/primaryExpression/identifier + <!-- or new variable with .length in pre-condition --> + | expression[1]/variableDeclaration[text()[1] = "="]/expression[text()[1] = ".length"]/expression/primaryExpression/identifier + ) + <!-- and array is neither public or external function argument --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text())] + <!-- nor internal or private function argument with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text())] + <!-- nor copied to local variable with memory visibility modifier --> + [not(text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text())] + ] + [condition/expression[matches(text()[1], ">|>=")]] +``` + +  + +``` +//forStatement + [ + ( <!-- either reused variable with .length in pre-condition --> + expression[1][text()[1] = "="]/expression[2][text()[1] = ".length"]/expression/primaryExpression/identifier + <!-- or new variable with .length in pre-condition --> + | expression[1]/variableDeclaration[text()[1] = "="]/expression[text()[1] = ".length"]/expression/primaryExpression/identifier + ) + [ <!-- and array is either public or external function argument --> + text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^public$|^external$")] or not(visibleType)]//parameter/identifier/text() + <!-- or internal or private function argument with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition[visibleType[matches(text()[1], "^private$|^internal$")]]//parameter[storageLocation/text() = "memory"]/identifier/text() + <!-- or copied to local variable with memory visibility modifier --> + or text()[1] = ancestor::functionDefinition//variableDeclaration[storageLocation/text() = "memory"]/identifier/text() + ] + ] + [condition/expression[matches(text()[1], ">|>=")]] +``` + +  + +``` + //whileStatement/condition + [ + not(descendant-or-self::functionCall) + and not(expression/expression/primaryExpression/numberLiteral/decimalNumber) + ] +``` + +  + +``` + //whileStatement[condition/descendant::functionCall] +``` + +### Sample Code + +``` +pragma solidity 0.4.24; + +contract GasLimitInLoops { + function foo() pure internal returns (uint) { + return(100); + } + + function testWhile() public { + uint x=0; + uint[] memory y; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 38f6c7 + while (x < foo()) { + } + while (x > 100) { + } + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 17f23a + while (y[5] < x) { + } + } + + function testFor(address[] _addr, uint amount) public { + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (uint i = 0; i < _addr.length; i++) { + } + + uint n = _addr.length; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < n; i++) { + } + + uint m; + m = _addr.length; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < m; i++) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (uint k; k < _addr.length; k++) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS v5j3d9 + for (i = _addr.length; i > 0; i--) { + } + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS v5j3d9 + for (uint j = _addr.length; j > 0; j--) { + } + } + + address[] stor; + + function testForMemory(address[] memory mem) { + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (uint i = 0; i < mem.length; i++) { + } + + uint n = mem.length; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < n; i++) { + } + + uint m; + m = mem.length; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < m; i++) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (uint k; k < mem.length; k++) { + } + + address[] memory mem2; + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < mem2.length; i++) { + } + + uint n2 = mem2.length; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < n2; i++) { + } + + uint m2; + m2 = mem2.length; + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (i = 0; i < m2; i++) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 4b7do5 + for (k = 0; k < mem2.length; k++) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS 12cf32 + for (uint j = stor.length; j > 0; j--) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS f6f853 + for (k = 0; k < stor.length; k++) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS v5j3d9 + for (i = mem.length; i > 0; i--) { + } + + // <yes> <report> SOLIDITY_GAS_LIMIT_IN_LOOPS v5j3d9 + for (j = mem2.length; j > 0; j--) { + } + } +} +``` + +### Abstract Syntax Tree + +[Click Here](https://astexplorer.net/#/gist/48d86c63521f85c514f9bb027b3a03f7/d30bac03e87f5ae246c611966f23bc3f7dcae9e9) to view the AST for the above code. Code generated from AST Explorer using _solidity-parser-antlr-0.4.11_ + + +### Code Result + +``` +SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 24 +column: 8 +content: for(uinti=0;i<_addr.length;i++){} + +ruleId: SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 39 +column: 8 +content: for(uintk;k<_addr.length;k++){} + +ruleId: SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 55 +column: 8 +content: for(uinti=0;i<mem.length;i++){} + +ruleId: SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 70 +column: 8 +content: for(uintk;k<mem.length;k++){} + +ruleId: SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 76 +column: 8 +content: for(i=0;i<mem2.length;i++){} + +ruleId: SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 91 +column: 8 +content: for(k=0;k<mem2.length;k++){} + +ruleId: SOLIDITY_EXTRA_GAS_IN_LOOPS +patternId: d3j11j +severity: 1 +line: 99 +column: 8 +content: for(k=0;k<stor.length;k++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 24 +column: 8 +content: for(uinti=0;i<_addr.length;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 29 +column: 8 +content: for(i=0;i<n;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 35 +column: 8 +content: for(i=0;i<m;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 39 +column: 8 +content: for(uintk;k<_addr.length;k++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 55 +column: 8 +content: for(uinti=0;i<mem.length;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 60 +column: 8 +content: for(i=0;i<n;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 66 +column: 8 +content: for(i=0;i<m;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 70 +column: 8 +content: for(uintk;k<mem.length;k++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 76 +column: 8 +content: for(i=0;i<mem2.length;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 81 +column: 8 +content: for(i=0;i<n2;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 87 +column: 8 +content: for(i=0;i<m2;i++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 91 +column: 8 +content: for(k=0;k<mem2.length;k++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: f6f853 +severity: 2 +line: 99 +column: 8 +content: for(k=0;k<stor.length;k++){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 12cf32 +severity: 2 +line: 43 +column: 8 +content: for(i=_addr.length;i>0;i--){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 12cf32 +severity: 2 +line: 46 +column: 8 +content: for(uintj=_addr.length;j>0;j--){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 12cf32 +severity: 2 +line: 95 +column: 8 +content: for(uintj=stor.length;j>0;j--){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 12cf32 +severity: 2 +line: 103 +column: 8 +content: for(i=mem.length;i>0;i--){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 12cf32 +severity: 2 +line: 107 +column: 8 +content: for(j=mem2.length;j>0;j--){} + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 17f23a +severity: 1 +line: 17 +column: 15 +content: y[5]<x + +ruleId: SOLIDITY_GAS_LIMIT_IN_LOOPS +patternId: 38f6c7 +severity: 2 +line: 12 +column: 8 +content: while(x<foo()){} + +ruleId: SOLIDITY_UPGRADE_TO_050 +patternId: 341gim +severity: 1 +line: 21 +column: 21 +content: address[]_addr + +ruleId: SOLIDITY_VISIBILITY +patternId: 910067 +severity: 1 +line: 52 +column: 4 +content: functiontestForMemory(address[]memorymem){for(uinti=0;i<mem.length;i++){}uintn=mem.length;for(i=0;i<n;i++){}uintm;m=mem.length;for(i=0;i<m;i++){}for(uintk;k<mem.length;k++){}address[]memorymem2;for(i=0;i<mem2.length;i++){}uintn2=mem2.length;for(i=0;i<n2;i++){}uintm2;m2=mem2.length;for(i=0;i<m2;i++){}for(k=0;k<mem2.length;k++){}for(uintj=stor.length;j>0;j--){}for(k=0;k<stor.length;k++){}for(i=mem.length;i>0;i--){}for(j=mem2.length;j>0;j--){}} + +ruleId: SOLIDITY_VISIBILITY +patternId: b51ce0 +severity: 1 +line: 50 +column: 4 +content: address[]stor; + +SOLIDITY_VISIBILITY :2 +SOLIDITY_EXTRA_GAS_IN_LOOPS :7 +SOLIDITY_UPGRADE_TO_050 :1 +SOLIDITY_GAS_LIMIT_IN_LOOPS :20 + +``` -- GitLab