Attackathon _ Fuel Network 33487 - [Smart Contract - Insight] Flags Do Not Affect Types Less Than u
Flags Do Not Affect Types Less Than u64
Submitted on Sun Jul 21 2024 20:43:48 GMT-0400 (Atlantic Standard Time) by @Blockian for Attackathon | Fuel Network
Report ID: #33487
Report type: Smart Contract
Report severity: Insight
Target: https://github.com/FuelLabs/sway/tree/v0.61.2
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
Description
Fuel Network bug report
Flags Do Not Affect Types Less Than u64
Description
Types smaller than u64 (u32, u16, and u8) are not influenced by user-set flags, leading to unintended behavior.
Root Cause
Since non-64-bit values are compiled to u64 under-the-hood, the ALU does not detect overflows. Therefore, every mathematical operation should manually perform overflow checks.
For instance, the add implementation includes such checks:
// Emulate overflowing arithmetic for non-64-bit integer types
impl Add for u32 {
fn add(self, other: Self) -> Self {
// any non-64-bit value is compiled to a u64 value under-the-hood
// constants (like Self::max() below) are also automatically promoted to u64
let res = __add(self, other);
if __gt(res, Self::max()) {
// integer overflow
__revert(0)
} else {
// no overflow
res
}
}
}Flags exist to indicate whether an overflow is allowed, such as the disable_panic_on_overflow function. However, since disable_panic_on_overflow disables panics caused by the ALU, it does not disable the panics triggered by types that manually check for overflows.
Impact
This issue affects the u32, u16, and u8 types in the Fuel ecosystem. Any project utilizing these types may experience unintended behavior in their contracts.
Proposed fix
Incorporate flag checks in mathematical operations involving u32, u16, and u8 types.
Proof of concept
Proof of Concept
Run the POC with forc test
contract;
use std::flags::{ disable_panic_on_overflow, enable_panic_on_overflow };
abi Tester {
fn add_with_overflow_u8(a: u8, b: u8) -> u8;
fn add_with_overflow_u64(a: u64, b: u64) -> u64;
}
impl Tester for Contract {
fn add_with_overflow_u8(a: u8, b: u8) -> u8 {
let _ = disable_panic_on_overflow();
let c = a + b;
let _ = enable_panic_on_overflow();
c
}
fn add_with_overflow_u64(a: u64, b: u64) -> u64 {
let _ = disable_panic_on_overflow();
let c = a + b;
let _ = enable_panic_on_overflow();
c
}
}
#[test]
fn test_increment_success() {
let caller = abi(Tester, CONTRACT_ID);
assert(caller.add_with_overflow_u64(u64::max(), 1) == 0); // works fine for u64
assert(caller.add_with_overflow_u8(u8::max(), 1u8) == 0u8); // reverts
}Last updated
Was this helpful?