From 33b7681e90ae1c0948f55f6fdb3828307a5bb4ed Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Mon, 8 May 2023 20:02:41 -0400 Subject: [PATCH 1/4] feat(cheatcodes): restrict cheatcodes on precompiles --- evm/src/executor/inspector/cheatcodes/env.rs | 9 ++++++++- evm/src/executor/inspector/cheatcodes/util.rs | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/evm/src/executor/inspector/cheatcodes/env.rs b/evm/src/executor/inspector/cheatcodes/env.rs index 90a6809ae1ac..3482dfb73949 100644 --- a/evm/src/executor/inspector/cheatcodes/env.rs +++ b/evm/src/executor/inspector/cheatcodes/env.rs @@ -3,7 +3,10 @@ use crate::{ abi::HEVMCalls, executor::{ backend::DatabaseExt, - inspector::cheatcodes::{util::with_journaled_account, DealRecord}, + inspector::cheatcodes::{ + util::{is_potential_precompile, with_journaled_account}, + DealRecord, + }, }, utils::{b160_to_h160, h160_to_b160, ru256_to_u256, u256_to_ru256}, }; @@ -224,6 +227,7 @@ pub fn apply( Bytes::new() } HEVMCalls::Store(inner) => { + ensure!(!is_potential_precompile(inner.0), "Store cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead"); data.journaled_state.load_account(h160_to_b160(inner.0), data.db)?; // ensure the account is touched data.journaled_state.touch(&h160_to_b160(inner.0)); @@ -237,6 +241,7 @@ pub fn apply( Bytes::new() } HEVMCalls::Load(inner) => { + ensure!(!is_potential_precompile(inner.0), "Load cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead"); // TODO: Does this increase gas usage? data.journaled_state.load_account(h160_to_b160(inner.0), data.db)?; let (val, _) = data.journaled_state.sload( @@ -249,6 +254,7 @@ pub fn apply( HEVMCalls::Breakpoint0(inner) => add_breakpoint(state, caller, &inner.0, true)?, HEVMCalls::Breakpoint1(inner) => add_breakpoint(state, caller, &inner.0, inner.1)?, HEVMCalls::Etch(inner) => { + ensure!(!is_potential_precompile(inner.0), "Etch cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead"); let code = inner.1.clone(); trace!(address=?inner.0, code=?hex::encode(&code), "etch cheatcode"); // TODO: Does this increase gas usage? @@ -258,6 +264,7 @@ pub fn apply( Bytes::new() } HEVMCalls::Deal(inner) => { + ensure!(!is_potential_precompile(inner.0), "Deal cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead"); let who = inner.0; let value = inner.1; trace!(?who, ?value, "deal cheatcode"); diff --git a/evm/src/executor/inspector/cheatcodes/util.rs b/evm/src/executor/inspector/cheatcodes/util.rs index d86b71a72346..58eb8ef69b33 100644 --- a/evm/src/executor/inspector/cheatcodes/util.rs +++ b/evm/src/executor/inspector/cheatcodes/util.rs @@ -350,6 +350,11 @@ pub fn check_if_fixed_gas_limit( && call_gas_limit > 2300 } +/// Small utility function that checks if an address is a potential precompile. +pub fn is_potential_precompile(address: H160) -> bool { + address < H160::from_low_u64_be(10) +} + #[cfg(test)] mod tests { use super::*; From 7f66161f7892e18adfd3f4e5caa92b7c0402b54a Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Mon, 8 May 2023 20:35:59 -0400 Subject: [PATCH 2/4] chore: exclude address(0) from precompiles check --- evm/src/executor/inspector/cheatcodes/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/executor/inspector/cheatcodes/util.rs b/evm/src/executor/inspector/cheatcodes/util.rs index 58eb8ef69b33..fe4827dfba20 100644 --- a/evm/src/executor/inspector/cheatcodes/util.rs +++ b/evm/src/executor/inspector/cheatcodes/util.rs @@ -352,7 +352,7 @@ pub fn check_if_fixed_gas_limit( /// Small utility function that checks if an address is a potential precompile. pub fn is_potential_precompile(address: H160) -> bool { - address < H160::from_low_u64_be(10) + address < H160::from_low_u64_be(10) && address != H160::zero() } #[cfg(test)] From 0f17d5f4c8863fa102c43970fbe00037bb83944a Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Mon, 8 May 2023 21:48:22 -0400 Subject: [PATCH 3/4] chore: fix test --- testdata/cheats/Deal.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testdata/cheats/Deal.t.sol b/testdata/cheats/Deal.t.sol index eabe5c72d737..efd37d585776 100644 --- a/testdata/cheats/Deal.t.sol +++ b/testdata/cheats/Deal.t.sol @@ -8,7 +8,7 @@ contract DealTest is DSTest { Cheats constant cheats = Cheats(HEVM_ADDRESS); function testDeal(uint256 amount) public { - address target = address(1); + address target = address(10); assertEq(target.balance, 0, "initial balance incorrect"); // Give half the amount From 26fe2ebf5a64588250e81c709d3ae538175733ae Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Tue, 9 May 2023 14:11:28 -0400 Subject: [PATCH 4/4] chore: add revert tests --- evm/src/executor/inspector/cheatcodes/env.rs | 1 - testdata/cheats/Etch.t.sol | 9 +++++++++ testdata/cheats/Load.t.sol | 7 +++++++ testdata/cheats/Store.t.sol | 10 ++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/evm/src/executor/inspector/cheatcodes/env.rs b/evm/src/executor/inspector/cheatcodes/env.rs index 3482dfb73949..006cf8de88fb 100644 --- a/evm/src/executor/inspector/cheatcodes/env.rs +++ b/evm/src/executor/inspector/cheatcodes/env.rs @@ -264,7 +264,6 @@ pub fn apply( Bytes::new() } HEVMCalls::Deal(inner) => { - ensure!(!is_potential_precompile(inner.0), "Deal cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead"); let who = inner.0; let value = inner.1; trace!(?who, ?value, "deal cheatcode"); diff --git a/testdata/cheats/Etch.t.sol b/testdata/cheats/Etch.t.sol index 1c1caf771de9..e92904dfc217 100644 --- a/testdata/cheats/Etch.t.sol +++ b/testdata/cheats/Etch.t.sol @@ -13,4 +13,13 @@ contract EtchTest is DSTest { cheats.etch(target, code); assertEq(string(code), string(target.code)); } + + function testEtchNotAvailableOnPrecompiles() public { + address target = address(1); + bytes memory code = hex"1010"; + cheats.expectRevert( + bytes("Etch cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead") + ); + cheats.etch(target, code); + } } diff --git a/testdata/cheats/Load.t.sol b/testdata/cheats/Load.t.sol index 2fc2e12de576..b2ab39761b50 100644 --- a/testdata/cheats/Load.t.sol +++ b/testdata/cheats/Load.t.sol @@ -26,6 +26,13 @@ contract LoadTest is DSTest { assertEq(val, 20, "load failed"); } + function testLoadNotAvailableOnPrecompiles() public { + cheats.expectRevert( + bytes("Load cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead") + ); + uint256 val = uint256(cheats.load(address(1), bytes32(0))); + } + function testLoadOtherStorage() public { uint256 val = uint256(cheats.load(address(store), bytes32(0))); assertEq(val, 10, "load failed"); diff --git a/testdata/cheats/Store.t.sol b/testdata/cheats/Store.t.sol index c5ef0c9261dc..ea9529877bd1 100644 --- a/testdata/cheats/Store.t.sol +++ b/testdata/cheats/Store.t.sol @@ -26,6 +26,16 @@ contract StoreTest is DSTest { assertEq(store.slot1(), 20, "store failed"); } + function testStoreNotAvailableOnPrecompiles() public { + assertEq(store.slot0(), 10, "initial value for slot 0 is incorrect"); + assertEq(store.slot1(), 20, "initial value for slot 1 is incorrect"); + + cheats.expectRevert( + bytes("Store cannot be used on precompile addresses (N < 10). Please use an address bigger than 10 instead") + ); + cheats.store(address(1), bytes32(0), bytes32(uint256(1))); + } + function testStoreFuzzed(uint256 slot0, uint256 slot1) public { assertEq(store.slot0(), 10, "initial value for slot 0 is incorrect"); assertEq(store.slot1(), 20, "initial value for slot 1 is incorrect");