Skip to content

Commit 5fe2694

Browse files
committed
host: Reject DELEGATECALL crossing EOF<>legacy boundary
1 parent 3b8e703 commit 5fe2694

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

test/state/host.cpp

+17-5
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,17 @@ uint256be Host::get_balance(const address& addr) const noexcept
7676

7777
namespace
7878
{
79+
bool is_eof(bytes_view code) noexcept
80+
{
81+
return code.size() >= 2 && code[0] == 0xEF && code[1] == 0x00;
82+
}
83+
7984
// For EXTCODE* instructions if the target is an EOF account, then only return EF00.
8085
// While we only do this if the caller is legacy, it is not a problem doing this
8186
// unconditionally, because EOF contracts dot no have EXTCODE* instructions.
8287
bytes_view extcode(bytes_view code) noexcept
8388
{
84-
if (code.size() >= 2 && code[0] == 0xEF && code[1] == 0x00)
85-
{
86-
return code.substr(2);
87-
}
88-
return code;
89+
return is_eof(code) ? code.substr(2) : code;
8990
}
9091
} // namespace
9192

@@ -281,6 +282,17 @@ evmc::Result Host::execute_message(const evmc_message& msg) noexcept
281282

282283
// Copy of the code. Revert will invalidate the account.
283284
const auto code = dst_acc != nullptr ? dst_acc->code : bytes{};
285+
286+
if (msg.kind == EVMC_DELEGATECALL)
287+
{
288+
// TODO: does the sender always have code here? or is this function used for EOAs too?
289+
const auto sender = m_state.get(msg.sender);
290+
291+
// DELEGATECALL initiator and destination both must be either legacy or EOF
292+
if (is_eof(code) != is_eof(sender.code))
293+
return evmc::Result{EVMC_FAILURE};
294+
}
295+
284296
return m_vm.execute(*this, m_rev, msg, code.data(), code.size());
285297
}
286298

0 commit comments

Comments
 (0)