diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 073639f381f..b02967aea81 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 db538d8b346..d1be28575de 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>; } @@ -224,9 +225,11 @@ impl RawSyscall { } } -impl Syscall for RawSyscall +impl Syscall for RawSyscall where F: FnOnce(&mut CallerWrap) -> Result<(Gas, T), HostError>, + Caller: AsContextExt>>, + Ext: BackendExternalities + 'static, { type Context = (); @@ -234,7 +237,10 @@ where self, caller: &mut CallerWrap, (): Self::Context, + syscall_name: SyscallName, ) -> Result<(Gas, T), HostError> { + caller.check_func_forbiddenness(syscall_name)?; + (self.0)(caller) } } @@ -285,9 +291,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.check_func_forbiddenness(syscall_name)?; caller.run_fallible::(gas, res_ptr, token, f) } } @@ -329,9 +337,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.check_func_forbiddenness(syscall_name)?; caller.run_any::(gas, token, f) } } @@ -352,6 +362,7 @@ where caller: &mut Caller, args: &[Value], builder: Builder, + syscall_name: SyscallName, ) -> Result where Builder: SyscallBuilder, @@ -365,7 +376,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 +1389,6 @@ where ) } - pub fn forbidden(_args: &[Value]) -> impl Syscall + use { - 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 c22111b9b1d..fb6016d92d0 100644 --- a/core-backend/src/mock.rs +++ b/core-backend/src/mock.rs @@ -32,7 +32,7 @@ use gear_core::{ gas::{ChargeError, CounterType, CountersOwner, GasAmount, GasCounter, GasLeft}, ids::{MessageId, ProgramId, ReservationId}, memory::{Memory, MemoryInterval}, - message::{HandlePacket, InitPacket, ReplyPacket}, + message::{HandlePacket, InitPacket, MessageContext, ReplyPacket}, pages::WasmPage, }; use gear_core_errors::{ReplyCode, SignalCode}; @@ -242,6 +242,9 @@ impl Externalities for MockExt { fn forbidden_funcs(&self) -> &BTreeSet { &self._forbidden_funcs } + fn msg_ctx(&self) -> &MessageContext { + unimplemented!() + } fn reserve_gas( &mut self, _amount: u64, diff --git a/core-backend/src/runtime.rs b/core-backend/src/runtime.rs index c6c05b28a54..c491647b5b7 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, @@ -160,4 +164,17 @@ where }, } } + + pub fn check_func_forbiddenness(&mut self, syscall_name: SyscallName) -> Result<(), HostError> { + if self.ext_mut().forbidden_funcs().contains(&syscall_name) + || self.ext_mut().msg_ctx().kind().forbids(syscall_name) + { + self.set_termination_reason( + ActorTerminationReason::Trap(TrapExplanation::ForbiddenFunction).into(), + ); + return Err(HostError); + } + + Ok(()) + } } diff --git a/core-processor/src/ext.rs b/core-processor/src/ext.rs index 40a22e557e6..966f006e38b 100644 --- a/core-processor/src/ext.rs +++ b/core-processor/src/ext.rs @@ -1420,6 +1420,10 @@ impl Externalities for Ext { fn forbidden_funcs(&self) -> &BTreeSet { &self.context.forbidden_funcs } + + fn msg_ctx(&self) -> &MessageContext { + &self.context.message_context + } } #[cfg(test)] diff --git a/core/src/env.rs b/core/src/env.rs index a14455484bc..169a31024d3 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 current message context. + fn msg_ctx(&self) -> &MessageContext; } diff --git a/core/src/message/context.rs b/core/src/message/context.rs index c922113bdf2..3f86288588d 100644 --- a/core/src/message/context.rs +++ b/core/src/message/context.rs @@ -244,6 +244,11 @@ impl MessageContext { &self.settings } + /// Getter for inner dispatch kind + pub fn kind(&self) -> DispatchKind { + self.kind + } + fn check_reply_availability(&self) -> Result<(), ExecutionError> { if !matches!(self.kind, DispatchKind::Init | DispatchKind::Handle) { return Err(ExecutionError::IncorrectEntryForReply); diff --git a/core/src/message/mod.rs b/core/src/message/mod.rs index 252d6807ea1..613762a4d19 100644 --- a/core/src/message/mod.rs +++ b/core/src/message/mod.rs @@ -42,7 +42,7 @@ pub use stored::{StoredDelayedDispatch, StoredDispatch, StoredMessage}; pub use user::{UserMessage, UserStoredMessage}; use super::buffer::LimitedVec; -use alloc::{collections::BTreeSet, string::String, vec::Vec}; +use alloc::{string::String, vec::Vec}; use core::fmt::Display; use gear_wasm_instrument::syscalls::SyscallName; use scale_info::{ @@ -195,23 +195,23 @@ impl DispatchKind { matches!(self, Self::Signal) } - /// Syscalls that are not allowed to be called for the dispatch kind. - pub fn forbidden_funcs(&self) -> BTreeSet { + /// Returns is syscall forbidden for the dispatch kind. + pub fn forbids(&self, syscall_name: SyscallName) -> bool { match self { - DispatchKind::Signal => [ - SyscallName::Source, - SyscallName::Reply, - SyscallName::ReplyPush, - SyscallName::ReplyCommit, - SyscallName::ReplyCommitWGas, - SyscallName::ReplyInput, - SyscallName::ReplyInputWGas, - SyscallName::ReservationReply, - SyscallName::ReservationReplyCommit, - SyscallName::SystemReserveGas, - ] - .into(), - _ => Default::default(), + DispatchKind::Signal => matches!( + syscall_name, + SyscallName::Source + | SyscallName::Reply + | SyscallName::ReplyPush + | SyscallName::ReplyCommit + | SyscallName::ReplyCommitWGas + | SyscallName::ReplyInput + | SyscallName::ReplyInputWGas + | SyscallName::ReservationReply + | SyscallName::ReservationReplyCommit + | SyscallName::SystemReserveGas + ), + _ => false, } } }