diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 72cc7342fe7..f2d39467d83 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -54,9 +54,10 @@ use gear_wasm_instrument::{ // we have requirement to pass function pointer for `gear_sandbox` // so the only reason this macro exists is const function pointers are not stabilized yet // so we create non-capturing closure that can be coerced into function pointer +#[rustfmt::skip] macro_rules! wrap_syscall { - ($func:ident) => { - |caller, args| FuncsHandler::execute(caller, args, FuncsHandler::$func) + ($func:ident, $syscall:ident) => { + |caller, args| FuncsHandler::execute(caller, args, FuncsHandler::$func, $syscall) }; } @@ -117,7 +118,6 @@ where // It makes adding functions to `EnvironmentDefinitionBuilder` shorter. struct EnvBuilder { env_def_builder: EnvironmentDefinitionBuilder>>, - forbidden_funcs: BTreeSet, funcs_count: usize, } @@ -133,12 +133,7 @@ where name: SyscallName, f: HostFuncType>>, ) { - if self.forbidden_funcs.contains(&name) { - self.env_def_builder - .add_host_func("env", name.to_str(), wrap_syscall!(forbidden)); - } else { - self.env_def_builder.add_host_func("env", name.to_str(), f); - } + self.env_def_builder.add_host_func("env", name.to_str(), f); self.funcs_count += 1; } @@ -167,63 +162,69 @@ where { #[rustfmt::skip] fn bind_funcs(builder: &mut EnvBuilder) { - builder.add_func(EnvVars, wrap_syscall!(env_vars)); - builder.add_func(BlockHeight, wrap_syscall!(block_height)); - builder.add_func(BlockTimestamp,wrap_syscall!(block_timestamp)); - builder.add_func(CreateProgram, wrap_syscall!(create_program)); - builder.add_func(CreateProgramWGas, wrap_syscall!(create_program_wgas)); - builder.add_func(Debug, wrap_syscall!(debug)); - builder.add_func(Panic, wrap_syscall!(panic)); - builder.add_func(OomPanic, wrap_syscall!(oom_panic)); - builder.add_func(Exit, wrap_syscall!(exit)); - builder.add_func(ReplyCode, wrap_syscall!(reply_code)); - builder.add_func(SignalCode, wrap_syscall!(signal_code)); - builder.add_func(ReserveGas, wrap_syscall!(reserve_gas)); - builder.add_func(ReplyDeposit, wrap_syscall!(reply_deposit)); - builder.add_func(UnreserveGas, wrap_syscall!(unreserve_gas)); - builder.add_func(GasAvailable, wrap_syscall!(gas_available)); - builder.add_func(Leave, wrap_syscall!(leave)); - builder.add_func(MessageId, wrap_syscall!(message_id)); - builder.add_func(ProgramId, wrap_syscall!(program_id)); - builder.add_func(Random, wrap_syscall!(random)); - builder.add_func(Read, wrap_syscall!(read)); - builder.add_func(Reply, wrap_syscall!(reply)); - builder.add_func(ReplyCommit, wrap_syscall!(reply_commit)); - builder.add_func(ReplyCommitWGas, wrap_syscall!(reply_commit_wgas)); - builder.add_func(ReplyPush, wrap_syscall!(reply_push)); - builder.add_func(ReplyTo, wrap_syscall!(reply_to)); - builder.add_func(SignalFrom, wrap_syscall!(signal_from)); - builder.add_func(ReplyWGas, wrap_syscall!(reply_wgas)); - builder.add_func(ReplyInput, wrap_syscall!(reply_input)); - builder.add_func(ReplyPushInput, wrap_syscall!(reply_push_input)); - builder.add_func(ReplyInputWGas, wrap_syscall!(reply_input_wgas)); - builder.add_func(Send, wrap_syscall!(send)); - builder.add_func(SendCommit, wrap_syscall!(send_commit)); - builder.add_func(SendCommitWGas, wrap_syscall!(send_commit_wgas)); - builder.add_func(SendInit, wrap_syscall!(send_init)); - builder.add_func(SendPush, wrap_syscall!(send_push)); - builder.add_func(SendWGas, wrap_syscall!(send_wgas)); - builder.add_func(SendInput, wrap_syscall!(send_input)); - builder.add_func(SendPushInput, wrap_syscall!(send_push_input)); - builder.add_func(SendInputWGas, wrap_syscall!(send_input_wgas)); - builder.add_func(Size, wrap_syscall!(size)); - builder.add_func(Source, wrap_syscall!(source)); - builder.add_func(Value, wrap_syscall!(value)); - builder.add_func(ValueAvailable, wrap_syscall!(value_available)); - builder.add_func(Wait, wrap_syscall!(wait)); - builder.add_func(WaitFor, wrap_syscall!(wait_for)); - builder.add_func(WaitUpTo, wrap_syscall!(wait_up_to)); - builder.add_func(Wake, wrap_syscall!(wake)); - builder.add_func(SystemReserveGas, wrap_syscall!(system_reserve_gas)); - builder.add_func(ReservationReply, wrap_syscall!(reservation_reply)); - builder.add_func(ReservationReplyCommit, wrap_syscall!(reservation_reply_commit)); - builder.add_func(ReservationSend, wrap_syscall!(reservation_send)); - builder.add_func(ReservationSendCommit, wrap_syscall!(reservation_send_commit)); - builder.add_func(SystemBreak, wrap_syscall!(system_break)); - - builder.add_func(Alloc, wrap_syscall!(alloc)); - builder.add_func(Free, wrap_syscall!(free)); - builder.add_func(FreeRange, wrap_syscall!(free_range)); + macro_rules! add_function { + ($syscall:ident, $func:ident) => { + builder.add_func($syscall, wrap_syscall!($func, $syscall)); + }; + } + + add_function!(EnvVars, env_vars); + add_function!(BlockHeight, block_height); + add_function!(BlockTimestamp, block_timestamp); + add_function!(CreateProgram, create_program); + add_function!(CreateProgramWGas, create_program_wgas); + add_function!(Debug, debug); + add_function!(Panic, panic); + add_function!(OomPanic, oom_panic); + add_function!(Exit, exit); + add_function!(ReplyCode, reply_code); + add_function!(SignalCode, signal_code); + add_function!(ReserveGas, reserve_gas); + add_function!(ReplyDeposit, reply_deposit); + add_function!(UnreserveGas, unreserve_gas); + add_function!(GasAvailable, gas_available); + add_function!(Leave, leave); + add_function!(MessageId, message_id); + add_function!(ProgramId, program_id); + add_function!(Random, random); + add_function!(Read, read); + add_function!(Reply, reply); + add_function!(ReplyCommit, reply_commit); + add_function!(ReplyCommitWGas, reply_commit_wgas); + add_function!(ReplyPush, reply_push); + add_function!(ReplyTo, reply_to); + add_function!(SignalFrom, signal_from); + add_function!(ReplyWGas, reply_wgas); + add_function!(ReplyInput, reply_input); + add_function!(ReplyPushInput, reply_push_input); + add_function!(ReplyInputWGas, reply_input_wgas); + add_function!(Send, send); + add_function!(SendCommit, send_commit); + add_function!(SendCommitWGas, send_commit_wgas); + add_function!(SendInit, send_init); + add_function!(SendPush, send_push); + add_function!(SendWGas, send_wgas); + add_function!(SendInput, send_input); + add_function!(SendPushInput, send_push_input); + add_function!(SendInputWGas, send_input_wgas); + add_function!(Size, size); + add_function!(Source, source); + add_function!(Value, value); + add_function!(ValueAvailable, value_available); + add_function!(Wait, wait); + add_function!(WaitFor, wait_for); + add_function!(WaitUpTo, wait_up_to); + add_function!(Wake, wake); + add_function!(SystemReserveGas, system_reserve_gas); + add_function!(ReservationReply, reservation_reply); + add_function!(ReservationReplyCommit, reservation_reply_commit); + add_function!(ReservationSend, reservation_send); + add_function!(ReservationSendCommit, reservation_send_commit); + add_function!(SystemBreak, system_break); + + add_function!(Alloc, alloc); + add_function!(Free, free); + add_function!(FreeRange, free_range); } } @@ -271,22 +272,10 @@ where use EnvironmentError::*; use SystemEnvironmentError::*; - let entry_forbidden = entry_point - .try_into_kind() - .as_ref() - .map(DispatchKind::forbidden_funcs) - .unwrap_or_default(); - let mut store = Store::new(None); let mut builder = EnvBuilder:: { env_def_builder: EnvironmentDefinitionBuilder::new(), - forbidden_funcs: ext - .forbidden_funcs() - .iter() - .copied() - .chain(entry_forbidden) - .collect(), funcs_count: 0, }; diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 9cd12764837..c345c3ab2e0 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -52,7 +52,7 @@ use gear_core::{ use gear_core_errors::{MessageError, ReplyCode, SignalCode}; use gear_sandbox::{AsContextExt, ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; -use gear_wasm_instrument::SystemBreakCode; +use gear_wasm_instrument::{SyscallName, SystemBreakCode}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithGas, ErrorWithHandle, ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Gas, Hash, HashWithValue, @@ -148,6 +148,7 @@ pub(crate) trait Syscall { self, caller: &mut CallerWrap, ctx: Self::Context, + syscall_name: SyscallName, ) -> Result<(Gas, T), HostError>; } @@ -234,6 +235,7 @@ where self, caller: &mut CallerWrap, (): Self::Context, + _syscall_name: SyscallName, ) -> Result<(Gas, T), HostError> { (self.0)(caller) } @@ -285,10 +287,11 @@ where self, caller: &mut CallerWrap, context: Self::Context, + syscall_name: SyscallName, ) -> Result<(Gas, ()), HostError> { let Self { token, f, .. } = self; let FallibleSyscallContext { gas, res_ptr } = context; - caller.run_fallible::(gas, res_ptr, token, f) + caller.run_fallible::(gas, res_ptr, token, syscall_name, f) } } @@ -329,10 +332,11 @@ where self, caller: &mut CallerWrap, ctx: Self::Context, + syscall_name: SyscallName, ) -> Result<(Gas, T), HostError> { let Self { token, f } = self; let InfallibleSyscallContext { gas } = ctx; - caller.run_any::(gas, token, f) + caller.run_any::(gas, token, syscall_name, f) } } @@ -352,6 +356,7 @@ where caller: &mut Caller, args: &[Value], builder: Builder, + syscall_name: SyscallName, ) -> Result where Builder: SyscallBuilder, @@ -365,7 +370,7 @@ where let (ctx, args) = Call::Context::from_args(args)?; let syscall = builder.build(args)?; - let (gas, value) = syscall.execute(&mut caller, ctx)?; + let (gas, value) = syscall.execute(&mut caller, ctx, syscall_name)?; let value = value.into(); Ok(WasmReturnValue { @@ -1378,12 +1383,6 @@ where ) } - pub fn forbidden(_args: &[Value]) -> impl Syscall { - InfallibleSyscall::new(CostToken::Null, |_: &mut CallerWrap| { - Err(ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into()) - }) - } - fn out_of_gas(ctx: &mut CallerWrap) -> UndefinedTerminationReason { let ext = ctx.ext_mut(); let current_counter = ext.current_counter_type(); diff --git a/core-backend/src/mock.rs b/core-backend/src/mock.rs index efd6b401e7c..c8e041c04fc 100644 --- a/core-backend/src/mock.rs +++ b/core-backend/src/mock.rs @@ -74,6 +74,7 @@ pub struct MockExt { reads: Vec, writes: Vec, _forbidden_funcs: BTreeSet, + _endpoint_forbidden_funcs: BTreeSet, } impl MockExt { @@ -242,6 +243,9 @@ impl Externalities for MockExt { fn forbidden_funcs(&self) -> &BTreeSet { &self._forbidden_funcs } + fn endpoint_forbidden_funcs(&self) -> &BTreeSet { + &self._endpoint_forbidden_funcs + } fn reserve_gas( &mut self, _amount: u64, diff --git a/core-backend/src/runtime.rs b/core-backend/src/runtime.rs index f9054d4ca0e..81994e5efc5 100644 --- a/core-backend/src/runtime.rs +++ b/core-backend/src/runtime.rs @@ -19,13 +19,17 @@ //! sp-sandbox runtime (here it's program execution state) realization. use crate::{ - error::{BackendAllocSyscallError, RunFallibleError, UndefinedTerminationReason}, + error::{ + ActorTerminationReason, BackendAllocSyscallError, RunFallibleError, TrapExplanation, + UndefinedTerminationReason, + }, memory::{BackendMemory, ExecutorMemory, MemoryAccessRegistry}, state::{HostState, State}, BackendExternalities, }; use gear_core::{costs::CostToken, pages::WasmPage}; use gear_sandbox::{AsContextExt, HostError}; +use gear_wasm_instrument::SyscallName; pub(crate) struct CallerWrap<'a, Caller> { pub caller: &'a mut Caller, @@ -75,12 +79,30 @@ where Ext: BackendExternalities + 'static, { #[track_caller] - pub fn run_any(&mut self, gas: u64, token: CostToken, f: F) -> Result<(u64, U), HostError> + pub fn run_any( + &mut self, + gas: u64, + token: CostToken, + syscall_name: SyscallName, + f: F, + ) -> Result<(u64, U), HostError> where F: FnOnce(&mut Self) -> Result, { self.state_mut().ext.decrease_current_counter_to(gas); + if self.ext_mut().forbidden_funcs().contains(&syscall_name) + || self + .ext_mut() + .endpoint_forbidden_funcs() + .contains(&syscall_name) + { + self.set_termination_reason( + ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into(), + ); + return Err(HostError); + } + let run = || { self.state_mut().ext.charge_gas_for_token(token)?; f(self) @@ -100,6 +122,7 @@ where gas: u64, res_ptr: u32, token: CostToken, + syscall_name: SyscallName, f: F, ) -> Result<(u64, ()), HostError> where @@ -109,6 +132,7 @@ where self.run_any( gas, token, + syscall_name, |ctx: &mut Self| -> Result<_, UndefinedTerminationReason> { let res = f(ctx); let res = ctx.process_fallible_func_result(res)?; diff --git a/core-processor/src/executor.rs b/core-processor/src/executor.rs index 4b0e6e0ba72..a5035b0bf85 100644 --- a/core-processor/src/executor.rs +++ b/core-processor/src/executor.rs @@ -115,6 +115,8 @@ where ); let value_counter = ValueCounter::new(value_available); + let endpoint_forbidden_funcs = kind.forbidden_funcs(); + let context = ProcessorContext { gas_counter, gas_allowance_counter, @@ -134,6 +136,7 @@ where existential_deposit: settings.existential_deposit, mailbox_threshold: settings.mailbox_threshold, costs: settings.ext_costs, + endpoint_forbidden_funcs, }; // Creating externalities. @@ -307,6 +310,12 @@ where ) .ok_or("Incorrect message store context: out of outgoing bytes limit")?; + let endpoint_forbidden_funcs = function + .try_into_kind() + .as_mut() + .map(|kind| kind.forbidden_funcs()) + .unwrap_or_default(); + let context = ProcessorContext { gas_counter: GasCounter::new(gas_limit), gas_allowance_counter: GasAllowanceCounter::new(gas_limit), @@ -333,6 +342,7 @@ where existential_deposit: Default::default(), mailbox_threshold: Default::default(), costs: Default::default(), + endpoint_forbidden_funcs, }; // Creating externalities. diff --git a/core-processor/src/ext.rs b/core-processor/src/ext.rs index 67a4985525c..710532b601e 100644 --- a/core-processor/src/ext.rs +++ b/core-processor/src/ext.rs @@ -88,6 +88,8 @@ pub struct ProcessorContext { pub program_candidates_data: BTreeMap>, /// Functions forbidden to be called. pub forbidden_funcs: BTreeSet, + /// Functions forbidden to be called with this endpoint + pub endpoint_forbidden_funcs: BTreeSet, /// Reserve for parameter of scheduling. pub reserve_for: u32, /// Output from Randomness. @@ -137,6 +139,7 @@ impl ProcessorContext { program_id: Default::default(), program_candidates_data: Default::default(), forbidden_funcs: Default::default(), + endpoint_forbidden_funcs: Default::default(), reserve_for: 0, random_data: ([0u8; 32].to_vec(), 0), gas_multiplier: gsys::GasMultiplier::from_value_per_gas(1), @@ -1418,6 +1421,10 @@ impl Externalities for Ext { fn forbidden_funcs(&self) -> &BTreeSet { &self.context.forbidden_funcs } + + fn endpoint_forbidden_funcs(&self) -> &BTreeSet { + &self.context.endpoint_forbidden_funcs + } } #[cfg(test)] diff --git a/core/src/env.rs b/core/src/env.rs index 63ab5b2d096..e3105c75f5a 100644 --- a/core/src/env.rs +++ b/core/src/env.rs @@ -391,4 +391,7 @@ pub trait Externalities { /// Return the set of functions that are forbidden to be called. fn forbidden_funcs(&self) -> &BTreeSet; + + /// Return the set of functions that are forbidden to be called in this endpoint. + fn endpoint_forbidden_funcs(&self) -> &BTreeSet; }