Attackathon _ Fuel Network 32728 - [Smart Contract - Low] Incorrect literal type inference
Submitted on Sun Jun 30 2024 23:56:39 GMT-0400 (Atlantic Standard Time) by @anatomist for Attackathon | Fuel Network
Report ID: #32728
Report type: Smart Contract
Report severity: Low
Target: https://github.com/FuelLabs/sway/tree/7b56ec734d4a4fda550313d448f7f20dba818b59
Impacts:
Incorrect sway compilation leading to incorrect bytecode
Description
Brief/Intro
Type inference from numeric literals to unsigned integer does not check the value, and might cause unexpected value truncation or illegal values.
Vulnerability Details
Sway is a strongly typed language, and must check variable types always match between operands. Similar to rust, sway automatically infers data types when possible if an explicit type is not provided. Type inference implies some of the checks that are usually done while constructing ast must be delayed until later, when types are actually inferred.
The numeric type is the primary user of type inference. During ast numeric value resolve, if the type of a numeric literal is not specified, it will use a generic TypeInfo::Numeric
type to store the literal.
Later during ir generation when the type of numeric literals expressions can be inferred, it will be casted to the respective type.
However, when casting to the actual unsigned integer type, the casted values are not checked, and may be silently truncated or incorrectly tagged.
The incorrect casting can have two kinds of results, the first type is silent truncation, where the value is truncated. While this is already problematic, it might be acceptable if the fuel team thinks this is the desired behavior. The assert
in the example succeeds because of the silent truncation.
The other is creating unsigned integers that exceed the max value of the type. The example below casts the numeric into a U64
unsigned integer, because u16
does not have its own dedicated type. Because of this, the value 4294967296 is stored into the u16 variable directly, and resulting a u16
that has a value greater than u16::max
. The assert
in the example fails because of the reaons described, and it is clearly not acceptible.
Impact Details
The incorrect type casting can unpredictable computation results, especially if we think about the variables that exceed the max possible value case. The exact impact is hard to estimate because it depends on how the affected contract is written, but loss of funds or bricking of contracts are both possible.
References
https://github.com/FuelLabs/sway/blob/fc2a90b78eb72d97e19100c93ca80c9a2892563c/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs#L2470
https://github.com/FuelLabs/sway/blob/46088782fbe6c01fca521a8067a3d61d7b58e848/sway-core/src/ir_generation/function.rs#L441
Proof of concept
Proof of Concept
The test case creates an u16
value that exceeds u16::max
and fails on assert.
Last updated