Attackathon _ Fuel Network 32291 - [Blockchain_DLT - Insight] Profiling is incorrect for dependent g

Submitted on Mon Jun 17 2024 12:00:07 GMT-0400 (Atlantic Standard Time) by @NinetyNineCrits for Attackathon | Fuel Network

Report ID: #32291

Report type: Blockchain/DLT

Report severity: Insight

Target: https://github.com/FuelLabs/fuel-vm/tree/0e46d324da460f2db8bcef51920fb9246ac2143b

Impacts:

  • Modification of transaction fees outside of design parameters

Description

Brief/Intro

Gas profiling for gas costs that depend on variable input is incorrect for large inputs or small amounts of context gas.

Vulnerability Details

There are 2 different gas charging cases: fixed and variable cost. The fixed cost variant uses gas_charge:

pub(crate) fn gas_charge(
    cgas: RegMut<CGAS>,
    ggas: RegMut<GGAS>,
    mut profiler: ProfileGas<'_>,
    gas: Word,
) -> SimpleResult<()> {
    profiler.profile(cgas.as_ref(), gas);
    gas_charge_inner(cgas, ggas, gas)
}

It can be seen that the profiler is invoked first to track the costs, before the charging happens.

In the variable cost case its the reverse:

Lets look at the internals of profiling and gas charging:

The function gas_charge_inner is responsible for decreasing the available gas (context gas, stored in register cgas) and is used by both fixed and variable case. As can be seen the function profile determines the gas it tracks as the minimum of the gas costs and the context gas (let gas_use = gas.min(*cgas);). The profiler assumes that cgas has not been deducted from yet and thats why it needs to be invoked first before any deductions happen.

An example were this will go wrong:

  • assume cgas = 1000, cost = 900

  • after deduction cgas = 100

  • profiler tracks min(900, 100) = 100, but should have tracked the cost of 900

Impact Details

For contexts with large variable cost or relatively little context gas, the gas will be tracked incorrectly. While the effects are not immediate, incorrect profiling is likely to cause inaccurate adjustments of variable costs. That can either lead to a loss for the protocol or overcharging of users

References

Not applicable

Proof of concept

Proof of Concept

add the following test to profile_gas.rs:

This will log:

note that the actual gas_used is 955, while the sum of the profiler tracked gas is 1+1+2+2+58+13=77, which is off by an order of magnitude.

If you reduce the input value for the last ALOC call (by setting op::movi(reg_b, 100000) instead of 200000), you will get correct tracking:

Last updated

Was this helpful?