From 0182efe3e0f9e466fc1731ca25cc633ea2a46e8b Mon Sep 17 00:00:00 2001 From: 0xSandyy <0xSandyy@gmail.com> Date: Wed, 5 Jun 2024 15:27:28 +0545 Subject: [PATCH 1/2] over/underflow vulnerability updated --- vulnerabilities/overflow-underflow.md | 76 +++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/vulnerabilities/overflow-underflow.md b/vulnerabilities/overflow-underflow.md index 5989e78..f4c324f 100644 --- a/vulnerabilities/overflow-underflow.md +++ b/vulnerabilities/overflow-underflow.md @@ -1,18 +1,74 @@ ## Integer Overflow and Underflow +In solidity, Integer types have maximum and minimum values. Integer overflow occurs when an integer variable exceeds the maximum value that can be stored in that variable type. Similarly, Integer underflow occurs when an integer variable goes below the minimum value for that variable type. Example: The maximum value ``uint8`` can store is ``255``. Now, when you store ``256`` in ``uint8`` it will overflow and the value will reset to 0. When you store ``257``, the value will be ``1``, ``2`` for ``258`` and so on. Similarly, if you try to store ``-1`` in the uint8 variable the value of the variable will become ``255``, and so on as it will underflow. -In solidity, integer types have maximum values. For example: +Some integer types and their min/max values: +| Type | Max | Min | +|----------|-------------|------| +| uint8 | 255 | 0 | +| uint16 | 65535 | 0 | +| uint24 | 16777215 | 0 | +| uint256 | 2^256 - 1 | 0 | -`uint8` => 255 -`uint16` => 65535 -`uint24` => 16777215 -`uint256` => (2^256) - 1 +Since smaller integer types like: ``uint8``, ``uint16``, etc have smaller maximum values, it can be easier to cause an overflow, thus they should be used with greater caution. -Overflow and underflow bugs can occur when you exceed the maximum value (overflow) or when you go below the minimum value (underflow). When you exceed the maximum value, you go back down to zero, and when you go below the minimum value, it brings you back up to the maximum value. +To prevent over/underflows, [Safe Math Library](https://github.com/ConsenSysMesh/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol) is often used by contracts with older versions of Solidity but Solidity >=0.8 protects against integer overflows and underflows through the use of built-in safe math functions. It's important to consider that regardless of SafeMath logic being used, either built-in or used manually in older contracts, over/underflows still trigger reverts, which may result in [denial of service](https://github.com/kadenzipfel/smart-contract-vulnerabilities/blob/master/vulnerabilities/dos-revert.md) of important functionality or other unexpected effects. Even after the update of solidity to 0.8, there are scenarios in which the integer overflow and underflow can still occur without the transaction reverting. -Since smaller integer types like: `uint8`, `uint16`, etc. have smaller maximum values, it can be easier to cause an overflow, thus they should be used with greater caution. +### Typecasting +The most common way in which integer over/underflow is possible when you convert an integer of a larger uint data type to a smaller data type. +```solidity +uint256 public a = 258; +uint8 public b = uint8(a); // typecasting uint256 to uint8 +``` -Older contracts often made use of the [SafeMath library](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol), to avoid over/underflows, but in solidity >=v0.8.0, SafeMath logic is built in by default. It's important to consider that regardless of SafeMath logic being used, either built-in or used manually in older contracts, over/underflows still trigger reverts, which may result in [denial of service](./dos-revert.md) of important functionality or other unexpected effects. Built-in SafeMath logic may also be avoided with `unchecked` blocks, [see docs for more info](https://docs.soliditylang.org/en/v0.8.15/control-structures.html?highlight=unchecked#checked-or-unchecked-arithmetic). +The above code snippet will overflow and the ``2`` will be stored in the variable ``b`` due to the fact that maximum value in uint8 data type is ``255``. So, it will overflow and reset to ``0`` without reverting. -### Sources +### Using Shift Operators +Overflow & underflow checks are not performed for shift operations like they are performed for other arithmetic operations. Thus, over/underflows can occur. -- https://consensys.github.io/smart-contract-best-practices/attacks/insecure-arithmetic/ +The left shift ``<<`` operator shifts all the beats in the first operand by the number specified in the second operand.Shifting an operand by 1 position is equivalent to multiplying it by 2, shifting 2 positions is equivalent to multiplying it by 4, and shifting 3 positions is equivalent to multiplying by 8. + +```solidity +uint8 public a = 100; +uint8 public b = 2; + +uint8 public c = a << b; // overflow as 100 * 4 > 255 +``` +In the above code, left shifting ``a`` which is ``100`` by 2 positions ``b`` is equivalent to multiplying 100 by 4. So the result will overflow and the value in c will be ``144`` because ``400-256`` is ``144``. + +### Use of Inline Assembly: +Inline Assembly in solidity is performed using YUL language. In YUL programming language, integer underflow & overflow is possible as compiler does not check automatically for it as YUL is a low-level language that is mostly used for making the code more optimized, which does this by omitting many opcodes. + +```solidity +uint8 public a = 255; + +function addition() public returns (uint8 result) { + +assembly { +result := add(sload(a.slot),1) // adding 1 will overflow and reset to 0 +// using inline assembly +} + +return result; +} +``` +In the above code we are adding ``1`` into the variable with inline assembly and then returning the result. The variable result will overflow and 0 will be returned, despite this the contract will not throw an error or revert. + +### Use of unchecked code block: +Performing arithmetic operations inside the unchecked block saves a lot of gas because it omits several checks and opcodes.But, some of these opcodes are used in default arithmetic operations in 0.8 to check for underflow/ overflow. + +```solidity +uint8 public a = 255; + +function uncheck() public{ + + unchecked { + a++; // overflow and reset to 0 without reverting + } + +} +``` +The unchecked code block is only recommended if you are sure that there is no possible way for the arithmetic to overflow or underflow. + +## Sources +1. https://docs.soliditylang.org/en/latest/080-breaking-changes.html +2. https://faizannehal.medium.com/how-solidity-0-8-protect-against-integer-underflow-overflow-and-how-they-can-still-happen-7be22c4ab92f From e063337001e9783900664a24b537c85e3c49b835 Mon Sep 17 00:00:00 2001 From: 0xSandyy <0xSandyy@gmail.com> Date: Thu, 6 Jun 2024 23:32:23 +0545 Subject: [PATCH 2/2] reviewed changes updated --- vulnerabilities/overflow-underflow.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/vulnerabilities/overflow-underflow.md b/vulnerabilities/overflow-underflow.md index f4c324f..24ba30e 100644 --- a/vulnerabilities/overflow-underflow.md +++ b/vulnerabilities/overflow-underflow.md @@ -25,7 +25,7 @@ The above code snippet will overflow and the ``2`` will be stored in the variabl ### Using Shift Operators Overflow & underflow checks are not performed for shift operations like they are performed for other arithmetic operations. Thus, over/underflows can occur. -The left shift ``<<`` operator shifts all the beats in the first operand by the number specified in the second operand.Shifting an operand by 1 position is equivalent to multiplying it by 2, shifting 2 positions is equivalent to multiplying it by 4, and shifting 3 positions is equivalent to multiplying by 8. +The left shift ``<<`` operator shifts all the beats in the first operand by the number specified in the second operand. Shifting an operand by 1 position is equivalent to multiplying it by 2, shifting 2 positions is equivalent to multiplying it by 4, and shifting 3 positions is equivalent to multiplying by 8. ```solidity uint8 public a = 100; @@ -42,19 +42,18 @@ Inline Assembly in solidity is performed using YUL language. In YUL programming uint8 public a = 255; function addition() public returns (uint8 result) { + assembly { + result := add(sload(a.slot), 1) // adding 1 will overflow and reset to 0 + // using inline assembly + } -assembly { -result := add(sload(a.slot),1) // adding 1 will overflow and reset to 0 -// using inline assembly -} - -return result; + return result; } ``` In the above code we are adding ``1`` into the variable with inline assembly and then returning the result. The variable result will overflow and 0 will be returned, despite this the contract will not throw an error or revert. ### Use of unchecked code block: -Performing arithmetic operations inside the unchecked block saves a lot of gas because it omits several checks and opcodes.But, some of these opcodes are used in default arithmetic operations in 0.8 to check for underflow/ overflow. +Performing arithmetic operations inside the unchecked block saves a lot of gas because it omits several checks and opcodes. But, some of these opcodes are used in default arithmetic operations in 0.8 to check for underflow/overflow. ```solidity uint8 public a = 255;