From e1860958dd725c3cd12222534510f29c6633223a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 11 Jul 2024 23:14:19 +0200 Subject: [PATCH] precompiles: Improve output buffer handling Replace the fixed-size on-stack temporary buffer for precompiles with a heap-allocated buffer big enough to handle properly any precompile invocation. This actually keeps the number of allocations the same. Previously the contents of the on-stack buffer were copied to heap by the Result constructor. Now we are creating the heap buffer in the first place and pass the ownership of it to the Result. This fixes out-of-bounds memory accesses often being found by fuzzers. --- test/state/precompiles.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/test/state/precompiles.cpp b/test/state/precompiles.cpp index 21b010f81e..37cea02ae2 100644 --- a/test/state/precompiles.cpp +++ b/test/state/precompiles.cpp @@ -364,19 +364,14 @@ evmc::Result call_precompile(evmc_revision rev, const evmc_message& msg) noexcep if (gas_left < 0) return evmc::Result{EVMC_OUT_OF_GAS}; - // Buffer for the precompile's output. - // Big enough to handle all "expmod" tests, but in case does not match the size requirement - // from analysis, the result will likely be incorrect. - // TODO: Replace with std::pmr::monotonic_buffer_resource? - uint8_t output_buf[4096]; - assert(std::size(output_buf) >= max_output_size); - + // Allocate buffer for the precompile's output and pass its ownership to evmc::Result. + // TODO: This can be done more elegantly by providing constructor evmc::Result(std::unique_ptr). + const auto output_data = new (std::nothrow) uint8_t[max_output_size]; const auto [status_code, output_size] = - execute(msg.input_data, msg.input_size, output_buf, std::size(output_buf)); - - evmc::Result result{ - status_code, status_code == EVMC_SUCCESS ? gas_left : 0, 0, output_buf, output_size}; - - return result; + execute(msg.input_data, msg.input_size, output_data, max_output_size); + const evmc_result result{status_code, status_code == EVMC_SUCCESS ? gas_left : 0, 0, + output_data, output_size, + [](const evmc_result* res) noexcept { delete[] res->output_data; }}; + return evmc::Result{result}; } } // namespace evmone::state