Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TOB-FUEL-30: Expensive instruction SWWQ with constant gas #566

Closed
xgreenx opened this issue Aug 28, 2023 · 1 comment
Closed

TOB-FUEL-30: Expensive instruction SWWQ with constant gas #566

xgreenx opened this issue Aug 28, 2023 · 1 comment
Labels
audit-report Issue from the audit report

Comments

@xgreenx
Copy link
Collaborator

xgreenx commented Aug 28, 2023

Description

The SWWQ (State write sequential 32 byte slots) instruction consumes constant gas, but its execution time depends linearly on the parameter D. The following figure shows the contract code which contains the expensive instructions.

Figure 30.1: Expensive instruction.

op::divi(0x11, RegId::HP, 32),
op::swwq(RegId::ZERO, 0x10, RegId::ZERO, 0x11), // expensive

The severity of this issue is limited by the fact that SWWQ checks the value of the parameter D, which is limited by the memory size. The contract above can be invoked as described in figure 29.2.
Similarly to #565, a loop bound by the parameter D causes a long execution time. The following figure shows the loop.

Figure 30.2: Loop based on the parameter D of SWWQ. (fuel-vm/fuel-vm/src/storage/memory.rs#379–414)

fn merkle_contract_state_range(
    &self,
    id: &ContractId,
    start_key: &Bytes32,
    range: Word,
) -> Result<Vec<Option<Cow<Bytes32>>>, Self::DataError> {
    let start: ContractsStateKey = (id, start_key).into();
    let end: ContractsStateKey = (id, &Bytes32::new([u8::MAX; 32])).into();
    let mut iter = self.memory.contract_state.range(start..end);
    let mut next_item = iter.next();
    Ok(std::iter::successors(Some(**start_key), |n| {
        let mut n = *n;
        if add_one(&mut n) {
        None
        } else {
        Some(n) }
        }) .map(...)
            .take(range as usize)
            .collect())
}

Exploit Scenario

An attacker deploys a contract that includes a malicious SWWQ instruction. With little gas an attacker can put a significant amount of stress on the network.

Recommendations

Short term, charge gas which dynamically depends on the parameter D.
Long term, deploy the fuzzer from the fuzzing appendix (see appendix E). By using a
reasonably low timeout of 100ms to 1s it is possible to catch bugs like this.

@xgreenx xgreenx added the audit-report Issue from the audit report label Aug 28, 2023
@xgreenx
Copy link
Collaborator Author

xgreenx commented Aug 28, 2023

Fixed with #537, requires follow-up PR on the fuel-core side FuelLabs/fuel-core#1325

@xgreenx xgreenx closed this as completed Aug 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
audit-report Issue from the audit report
Projects
None yet
Development

No branches or pull requests

1 participant