IllIllI - Operations may overflow when sign is flipped from negative to positive
sherlock-admin opened this issue · comments
IllIllI
medium
Operations may overflow when sign is flipped from negative to positive
Summary
Operations may overflow when signs are flipped from negatives to positives, causing orders to get canceled incorrectly
Vulnerability Detail
There are many places in the code where the sign of an int256
is flipped, and the value is assigned to a uint256
. The way this is done is by prepending a negative sign to the value, then casting, which is not a safe operation and may trigger an overflow.
Most places are unable to overflow because they don't get negative enough, but one of the places where it's possible, and there is protection attempted to prevent it, is when the virtual inventory is assigned as the open interest in getNextOpenInterestForVirtualInventory()
Impact
The assignment will revert with an overflow exception, which will cause market orders to get canceled when it was not necessary for them to be, including liquidation and ADL orders, which may have prevented subsequent overflows.
Code Snippet
Negation without an unchecked block happens prior to the overflow adjustment
// File: gmx-synthetics/contracts/pricing/PositionPricingUtils.sol : PositionPricingUtils.getNextOpenInterestForVirtualInventory() #1
310 // if virtualInventory is more than zero it means that
311 // tokens were virtually sold to the pool, so set shortOpenInterest
312 // to the virtualInventory value
313 // if virtualInventory is less than zero it means that
314 // tokens were virtually bought from the pool, so set longOpenInterest
315 // to the virtualInventory value
316 if (virtualInventory > 0) {
317 shortOpenInterest = virtualInventory.toUint256();
318 } else {
319 @> longOpenInterest = (-virtualInventory).toUint256();
320 }
321
322 // the virtual long and short open interest is adjusted by the usdDelta
323 // to prevent an overflow in getNextOpenInterestParams
324 // price impact depends on the change in USD balance, so offsetting both
325 // values equally should not change the price impact calculation
326 @> if (params.usdDelta < 0) {
327 uint256 offset = (-params.usdDelta).toUint256();
328 longOpenInterest += offset;
329: shortOpenInterest += offset;
This test shows that using negation will result in an overflow when the value is equal to type(int256).min
, unless the operation is in an unchecked
block:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "forge-std/Test.sol";
contract It is Test {
function testIt() external view returns (uint256) {
uint256 tmp;
console.log("max:\t");
console.logInt(type(int256).max);
console.log("min:\t");
console.logInt(type(int256).min);
unchecked {
tmp = uint256(-type(int256).min); // doesn't overflow
console.log("tmp:\t");
console.log(tmp);
}
console.log("prior to no unchecked block");
tmp = uint256(-type(int256).min); // overflows
return tmp;
}
}
Output:
$ forge test -vv
[⠑] Compiling...
No files changed, compilation skipped
Running 1 test for src/T.sol:It
[FAIL. Reason: Arithmetic over/underflow] testIt():(uint256) (gas: 6346)
Logs:
max:
57896044618658097711785492504343953926634992332820282019728792003956564819967
min:
-57896044618658097711785492504343953926634992332820282019728792003956564819968
tmp:
57896044618658097711785492504343953926634992332820282019728792003956564819968
prior to no unchecked block
Test result: FAILED. 0 passed; 1 failed; finished in 807.41µs
Failing tests:
Encountered 1 failing test in src/T.sol:It
[FAIL. Reason: Arithmetic over/underflow] testIt():(uint256) (gas: 6346)
Encountered a total of 1 failing tests, 0 tests succeeded
Tool used
Manual Review
Recommendation
Use OpenZeppelin's SignedMath.abs()
, which does the flip under an unchecked
block, everywhere you currently use negative signs to change a negative value to a positive one.
would classify this as a low since it is very unlikely for overflow to occur for those values as well
"The vulnerability must be something that is not considered an acceptable risk by a reasonable protocol team." https://docs.sherlock.xyz/audits/judging/judging . This one is marked as disputed and there is no fix, so closing