Skip to content

range(start, start + N) reverts for negative numbers

Low
charles-cooper published GHSA-ppx5-q359-pvwj Apr 25, 2024

Package

pip vyper (pip)

Affected versions

>=0.3.8, <=0.3.10

Patched versions

0.4.0

Description

Summary

When looping over a range of the form range(start, start + N), if start is negative, the execution will always revert.

Details

This issue is caused by an incorrect assertion inserted by the code generation of the range (stmt.parse_For_range()):

vyper/vyper/codegen/stmt.py

Lines 286 to 287 in 9136169

_, hi = start.typ.int_bounds
start = clamp("le", start, hi + 1 - rounds)

This assertion was introduced in 3de1415 to fix GHSA-6r8q-pfpv-7cgj. The issue arises when start is signed, instead of using sle, le is used and start is interpreted as an unsigned integer for the comparison. If it is a negative number, its 255th bit is set to 1 and is hence interpreted as a very large unsigned integer making the assertion always fail.

PoC

@external
def foo():
    x:int256 = min_value(int256)
    # revert when it should not since we have the following assertion that fails:
    # [assert, [le, min_value(int256), max_value(int256) + 1 - 10]],
    for i in range(x, x + 10):
        pass

Patches

patched in v0.4.0, specifically, #3679 disallows this form of range().

Impact

Any contract having a range(start, start + N) where start is a signed integer with the possibility for start to be negative is affected. If a call goes through the loop while supplying a negative start the execution will revert.

Severity

Low

CVE ID

CVE-2024-32481

Weaknesses

No CWEs

Credits