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

Precompile Execution Without Sufficient Gas In Kakarot #74

Closed
howlbot-integration bot opened this issue Oct 27, 2024 · 8 comments
Closed

Precompile Execution Without Sufficient Gas In Kakarot #74

howlbot-integration bot opened this issue Oct 27, 2024 · 8 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue grade-b primary issue Highest quality submission among a set of duplicates QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax 🤖_primary AI based primary recommendation 🤖_39_group AI based duplicate group recommendation sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sufficient quality report This report is of sufficient quality

Comments

@howlbot-integration
Copy link

Lines of code

https://github.com/kkrt-labs/kakarot/blob/7411a5520e8a00be6f5243a50c160e66ad285563/src/kakarot/interpreter.cairo#L79-L100

Vulnerability details

Impact

Precompiles in Kakarot can execute computationally expensive operations before verifying sufficient gas is available, leading to:

  • Free computation at the expense of the Starknet paymaster who covers Cairo step costs
  • Deviation from Ethereum's behavior where precompiles require upfront gas checks

The issue exists because while EVM gas would be charged preventing true "free" execution, the underlying Starknet Cairo program steps are executed during the precompile computation before the gas check. These computational costs are covered by the paymaster, not the EVM transaction sender.

Proof of Concept

Executing precompiles before verifying gas in Kakarot's:

	let (output_len, output, gas_used, revert_code) = Precompiles.exec_precompile(
		evm.message.code_address.evm,
		evm.message.calldata_len,
		evm.message.calldata,
		caller_code_address,
		caller_address,
	);

	let precompile_reverted = is_not_zero(revert_code);
	if (precompile_reverted != FALSE) {
		// No need to charge gas as precompiles can only trigger EXCEPTIONAL_REVERT
		// which will consume the entire gas of the context.
		let evm = EVM.stop(evm, output_len, output, revert_code);
		tempvar range_check_ptr = range_check_ptr;
		tempvar evm = evm;
	} else {
		// Charge gas before stopping
		let evm = EVM.charge_gas(evm, gas_used);
		let evm = EVM.stop(evm, output_len, output, evm.reverted);
		tempvar range_check_ptr = range_check_ptr;
		tempvar evm = evm;
	}

Interpreter.cairo:L79

By contrast, Geth performs gas validation before execution in:

func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
	gasCost := p.RequiredGas(input)
	if suppliedGas < gasCost {
		return nil, 0, ErrOutOfGas
	}
	if logger != nil && logger.OnGasChange != nil {
		logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
	}
	suppliedGas -= gasCost
	output, err := p.Run(input)
	return output, suppliedGas, err
}

core/vm/contracts.go:L223

Flow:

sequenceDiagram
    actor Attacker
    participant Kakarot
    participant Precompile
    participant Starknet

    
    rect rgb(0,0,0)
    Note over Attacker,Starknet: Kakarot Implementation (Vulnerable)
        Attacker->>Kakarot: Call precompile with insufficient gas
        activate Kakarot
        Kakarot->>Precompile: Execute computation
        activate Precompile
        Note right of Precompile: Cairo steps executed!
        Precompile-->>Kakarot: Return result
        deactivate Precompile
        Kakarot->>Kakarot: Check gas (Too late!)
        Note right of Kakarot: Transaction reverts but<br/>computation already done
        Kakarot-->>Attacker: Revert
        deactivate Kakarot
    end


Loading

Key differences:

  • Geth validates gas availability before any precompile execution, preventing any computation without sufficient gas
  • Kakarot executes first, checks gas later
  • In Kakarot, Cairo computation costs are already incurred when gas check fails

Tools Used

Manual Review

Recommended Mitigation Steps

Add upfront gas validation before precompile execution by implementing a check_precompile_gas function that validates available gas. Only proceed with execution if sufficient gas exists, otherwise revert immediately with an out-of-gas error.

Assessed type

Other

@howlbot-integration howlbot-integration bot added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value 🤖_39_group AI based duplicate group recommendation 🤖_primary AI based primary recommendation bug Something isn't working primary issue Highest quality submission among a set of duplicates sufficient quality report This report is of sufficient quality labels Oct 27, 2024
howlbot-integration bot added a commit that referenced this issue Oct 27, 2024
@ClementWalter
Copy link

Severity: Invalid

Comment: Kakarot paymaster can decide to not relay the tx.

@ClementWalter ClementWalter added the sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue label Nov 4, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Nov 7, 2024

dmvt marked the issue as unsatisfactory:
Invalid

@c4-judge c4-judge closed this as completed Nov 7, 2024
@c4-judge c4-judge added the unsatisfactory does not satisfy C4 submission criteria; not eligible for awards label Nov 7, 2024
@koolexcrypto
Copy link

Hi @dmvt,

Kakarot's implementation violates fundamental EVM gas accounting rules as defined in the Yellow Paper:

  1. Explicit Precompile Gas Ordering
    From equation (209) in Appendix E, precompile execution is strictly defined:
ΞPRE(σ, g, A, I) ≡ {
    (∅, 0, A, ()) if g < gr
    (σ, g - gr, A, o) otherwise
}

This specification has two critical requirements:

  • If insufficient gas (g < gr), execution must immediately return with empty output () indicating no computation
  • If sufficient gas, gas must be deducted (g - gr) BEFORE any execution that produces output o

The current implementation violates both by executing first and attempting to charge gas after computation.

  1. Gas as Prerequisite for Computation
    Section 5 of the Yellow Paper establishes gas as a fundamental prerequisite:

"In order to avoid issues of network abuse and to sidestep the inevitable questions stemming from Turing completeness, all programmable computation in Ethereum is subject to fees."

The phrase "subject to fees" means gas checks and deductions must precede computation, not follow it.

Kakarot execute precompiles before gas checks and deduction which represents a clear violation of the EVM specification.

The only compliant implementation is to:

  1. Validate gas sufficiency
  2. Deduct required gas amount
  3. Only then proceed with precompile computation

This matches both the letter and intent of the Yellow Paper's specification.

I appreciate you having a second look at this 🙏.

@c4-judge
Copy link
Contributor

dmvt removed the grade

@c4-judge c4-judge reopened this Nov 12, 2024
@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed unsatisfactory does not satisfy C4 submission criteria; not eligible for awards 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Nov 12, 2024
@c4-judge
Copy link
Contributor

dmvt changed the severity to QA (Quality Assurance)

@dmvt
Copy link

dmvt commented Nov 12, 2024

Point well taken. Adjusted to QA / low risk.

@c4-judge
Copy link
Contributor

dmvt marked the issue as grade-b

@ClementWalter
Copy link

ok for QA

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue grade-b primary issue Highest quality submission among a set of duplicates QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax 🤖_primary AI based primary recommendation 🤖_39_group AI based duplicate group recommendation sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

5 participants