Arithmetic overflow in Substrate occurs when arithmetic operations are performed using primitive operations instead of specialized functions that check for overflow. When a Substrate node is compiled in debug
mode, integer overflows will cause the program to panic. However, when the node is compiled in release
mode (e.g. cargo build --release
), Substrate will perform two's complement wrapping. A production-ready node will be compiled in release
mode, which makes it vulnerable to arithmetic overflow.
In the pallet-overflow
pallet, notice that the transfer
function sets update_sender
and update_to
using primitive arithmetic operations.
/// Allow minting account to transfer a given balance to another account.
///
/// Parameters:
/// - `to`: The account to receive the transfer.
/// - `amount`: The amount of balance to transfer.
///
/// Emits `Transferred` event when successful.
#[pallet::weight(10_000)]
pub fn transfer(
origin: OriginFor<T>,
to: T::AccountId,
amount: u64,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
let sender_balance = Self::get_balance(&sender);
let receiver_balance = Self::get_balance(&to);
// Calculate new balances.
let update_sender = sender_balance - amount;
let update_to = receiver_balance + amount;
[...]
}
The sender of the extrinsic can exploit this vulnerability by causing update_sender
to underflow, which artificially inflates their balance.
Note: Aside from the stronger mitigations mentioned below, a check to make sure that sender
has at least amount
balance would have also prevented an underflow.
- Use
checked
orsaturating
functions for arithmetic operations.