Skip to content

Incorrect balance handling in nested contract calls

Critical
abizjak published GHSA-44wx-3q8j-r8qr Aug 15, 2022

Package

concordium-node (Rust, Haskell)

Affected versions

<= 4.2.1

Patched versions

4.2.3, 4.n.* for n >= 3, 5+

Description

Impact

All released node versions between versions 4 and 4.2.1 contain a bug which can be triggered by certain transactions involving smart contracts.
This bug can lead to either the node stopping to bake, or to crashing, depending on whether the transaction is part of a block or not.

References

The bug is caused by incorrect balance tracking in the scheduler, specifically in the case of nested contract calls with interruptions.
In order to support the get_receive_self_balance call the scheduler must keep track of the current balance of the contract during execution of the transaction. This balance can change as a result of both actions of the contract, as well as other accounts or contracts.

A representative scenario where a bug occurs is in a transaction that triggers the following sequence of actions

  1. Account A transfers CCD to contract C
  2. Contract C invokes itself, say an entrypoint E
  3. Execution of E triggers a transfer to some account, A'.
  4. After the transfer, in the execution of E the contract calls get_receive_self_balance. If the initial transfer from A to C was non-zero then the return value here will be incorrect. Concretely, if the balance of the contract before the transaction was 0, and the transfer was m, then the observed balance would be 2m.

The error in balance tracking here means that the contract is then allowed to invoke, e.g., a transfer of 2m to an account. This leads to a precondition violation in the scheduler when it tries to affect the transfer, which leads to the node crashing.

Severity

Critical

CVE ID

No known CVE

Weaknesses

No CWEs