TOCTOU bugs in ActionHandler
Description
The action-handler system in Penumbra works by running the checks of actions in parallel such that side effects of the execution of an action do not affect the checks of another action in the same transaction.
A more concise example of this would be the below call trace:
Action 1 -> check_stateless
Action 2 -> check_stateless
...
Action N -> check_stateless
Action 1 -> check_stateful
Action 2 -> check_stateful
...
Action N -> check_stateful
Action 1 -> execute
Action 2 -> execute
...
Action N -> execute
This causes issues where developers could expect these checks to act like the transaction handling in Cosmos, which is instead dispatched like this:
Action 1 -> check_stateless
Action 1 -> check_stateful
Action 1 -> execute
Action 2 -> check_stateless
Action 2 -> check_stateful
Action 2 -> execute
Action N -> check_stateless
Action N -> check_stateful
Action N -> execute
This mismatch between the intuitive mental model of sequential execution of each action's methods with the actual interleaved order leads to time-of-check time-of-use (TOCTOU) bugs, where Action 1's execute
modifies the state that was already checked by Action 2's check_stateful
, and then Action 2's execute
proceeds as if its check_stateful
's checks still held. Mitigating these bugs efficiently can often be done by ensuring that there is a corresponding check in Transaction::check_stateless
that ensures that multiple actions within the same transaction do not modify the same state.
Impact
Actions such as BridgeSudoChange
can be executed twice when not expected. Imagine a scenario where the sudo address of the bridge was 0x4141...
.
In one transaction with two messages from 0x4141...
, two bridge sudo change actions are included: the first changing the sudo address to 0x4242...
and the second changing it to 0x4343...
.
It is expected that only the first sudo bridge change action is successful as the second action would no longer be sent by the sudo address. However, with the current action architecture, the second transaction would also be successful.
This applies to all actions; however, it mainly affects actions that rely on state that they themselves change.
Recommendations
Modify the action handling to run the actions in sequence, or be aware of the possibilities and move important checks into execute
.