#38169 [SC-Insight] Deferred Evaluation Of `Default_Return_Value` May Skip Side Effect Execution
Submitted on Dec 26th 2024 at 21:17:32 UTC by @anatomist for Attackathon | Ethereum Protocol
Report ID: #38169
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/vyperlang/vyper
Impacts:
(Compiler) Incorrect bytecode generation leading to incorrect behavior
(Compiler) Unexpected behavior
Description
Brief/Intro
Calls to external contracts has four additional kwargs that allow user to tune the behavior of the call. Within those kwargs, default_return_value
specifies what to use as return value when the callee contract does not return anything. However, deferred evaluation of the expression for default_return_value
may result in it being executed at the wrong time, or worse, skipped altogether along with any side effects it has.
Vulnerability Details
The _unpack_returndata
is responsible for decoding data returned from an external call. It also injects the default_return_value
as return data if the returndatasize == 0
However, since default_return_value
is not cached with cache_when_complex
prior to the external call, the evaluation is deferred until expression value is actually used. This creates an interesting scenario, if the expr for default_return_value
contains side effects, it might be skipped. For example, in the PoC below, get_default_id
only gets called if the external call doesn't return any data, and the side effect of increasing external_call_counter
might be skipped.
This implementation is confusing from language users' point of view, since it is reasonable to expect all arguments of a function to be evaluated prior to the function call itself. We believe the "correct" language design would be to cache the expr
of default_return_value
, so it gets executed before the external call, regardless of the returned result.
Additionally, we also noticed another small "mistake" in the default value assignment code, where the following "legal" code fails to compile.
This is due to make_setter
not able to assign values from VYPER encoding pointers to ABI encoding pointers
Impact Details
Unforeseen deferred evaluation or unevaluated code can result in all kinds of unexpected behaviors in a contract, such as skipping critical checks performed in the code, skipping important business logic, and more. This exposes language users to substantial risks.
References
https://github.com/vyperlang/vyper/blob/9c98b3ed4a4fbb1a614e63f815617fc275a0d16a/vyper/codegen/external_call.py#L157
https://github.com/vyperlang/vyper/blob/9c98b3ed4a4fbb1a614e63f815617fc275a0d16a/vyper/codegen/external_call.py#L156
https://github.com/vyperlang/vyper/blob/9c98b3ed4a4fbb1a614e63f815617fc275a0d16a/vyper/codegen/core.py#L1013
https://github.com/vyperlang/vyper/blob/9c98b3ed4a4fbb1a614e63f815617fc275a0d16a/vyper/codegen/core.py#L1044
Proof of Concept
Proof of Concept
Already shown in Vulnerability Details section.
Was this helpful?