diff --git a/.changelog/unreleased/bug-fixes/1902-validate-wasm.md b/.changelog/unreleased/bug-fixes/1902-validate-wasm.md new file mode 100644 index 0000000000..a6c5587000 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/1902-validate-wasm.md @@ -0,0 +1,2 @@ +- Added wasm validation in `init_chain` and in client utils. + ([\#1902](https://github.com/anoma/namada/pull/1902)) \ No newline at end of file diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 7ef136bc98..83e9cee5e1 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -1898,6 +1898,7 @@ pub mod cmds { pub enum Utils { JoinNetwork(JoinNetwork), FetchWasms(FetchWasms), + ValidateWasm(ValidateWasm), InitNetwork(InitNetwork), InitGenesisValidator(InitGenesisValidator), PkToTmAddress(PkToTmAddress), @@ -1913,6 +1914,8 @@ pub mod cmds { let join_network = SubCmd::parse(matches).map(Self::JoinNetwork); let fetch_wasms = SubCmd::parse(matches).map(Self::FetchWasms); + let validate_wasm = + SubCmd::parse(matches).map(Self::ValidateWasm); let init_network = SubCmd::parse(matches).map(Self::InitNetwork); let init_genesis = @@ -1924,6 +1927,7 @@ pub mod cmds { let epoch_sleep = SubCmd::parse(matches).map(Self::EpochSleep); join_network .or(fetch_wasms) + .or(validate_wasm) .or(init_network) .or(init_genesis) .or(pk_to_tm_address) @@ -1937,6 +1941,7 @@ pub mod cmds { .about("Utilities.") .subcommand(JoinNetwork::def()) .subcommand(FetchWasms::def()) + .subcommand(ValidateWasm::def()) .subcommand(InitNetwork::def()) .subcommand(InitGenesisValidator::def()) .subcommand(PkToTmAddress::def()) @@ -1985,6 +1990,28 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct ValidateWasm(pub args::ValidateWasm); + + impl SubCmd for ValidateWasm { + const CMD: &'static str = "validate-wasm"; + + fn parse(matches: &ArgMatches) -> Option { + matches + .subcommand_matches(Self::CMD) + .map(|matches| Self(args::ValidateWasm::parse(matches))) + } + + fn def() -> App { + App::new(Self::CMD) + .about( + "Check that the provided wasm code is valid by the Namada \ + standards.", + ) + .add_args::() + } + } + #[derive(Clone, Debug)] pub struct InitNetwork(pub args::InitNetwork); @@ -5481,6 +5508,26 @@ pub mod args { } } + #[derive(Clone, Debug)] + pub struct ValidateWasm { + pub code_path: PathBuf, + } + + impl Args for ValidateWasm { + fn parse(matches: &ArgMatches) -> Self { + let code_path = CODE_PATH.parse(matches); + Self { code_path } + } + + fn def(app: App) -> App { + app.arg( + CODE_PATH + .def() + .help("The path to the wasm file to validate."), + ) + } + } + #[derive(Clone, Debug)] pub struct InitNetwork { pub genesis_path: PathBuf, diff --git a/apps/src/lib/cli/client.rs b/apps/src/lib/cli/client.rs index 675c5b4aea..b0991d8c0d 100644 --- a/apps/src/lib/cli/client.rs +++ b/apps/src/lib/cli/client.rs @@ -634,6 +634,9 @@ impl CliApi { Utils::FetchWasms(FetchWasms(args)) => { utils::fetch_wasms(global_args, args).await } + Utils::ValidateWasm(ValidateWasm(args)) => { + utils::validate_wasm(args) + } Utils::InitNetwork(InitNetwork(args)) => { utils::init_network(global_args, args) } diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs index 77b18f9136..180f36865c 100644 --- a/apps/src/lib/client/utils.rs +++ b/apps/src/lib/client/utils.rs @@ -15,6 +15,7 @@ use namada::types::address; use namada::types::chain::ChainId; use namada::types::dec::Dec; use namada::types::key::*; +use namada::vm::validate_untrusted_wasm; use prost::bytes::Bytes; use rand::prelude::ThreadRng; use rand::thread_rng; @@ -363,6 +364,17 @@ pub async fn fetch_wasms_aux(base_dir: &Path, chain_id: &ChainId) { wasm_loader::pre_fetch_wasm(&wasm_dir).await; } +pub fn validate_wasm(args::ValidateWasm { code_path }: args::ValidateWasm) { + let code = std::fs::read(code_path).unwrap(); + match validate_untrusted_wasm(code) { + Ok(()) => println!("Wasm code is valid"), + Err(e) => { + eprintln!("Wasm code is invalid: {e}"); + cli::safe_exit(1) + } + } +} + /// Length of a Tendermint Node ID in bytes const TENDERMINT_NODE_ID_LENGTH: usize = 20; diff --git a/apps/src/lib/node/ledger/shell/init_chain.rs b/apps/src/lib/node/ledger/shell/init_chain.rs index b650e2d730..ceb4e9c446 100644 --- a/apps/src/lib/node/ledger/shell/init_chain.rs +++ b/apps/src/lib/node/ledger/shell/init_chain.rs @@ -19,6 +19,7 @@ use namada::types::hash::Hash as CodeHash; use namada::types::key::*; use namada::types::time::{DateTimeUtc, TimeZone, Utc}; use namada::types::token; +use namada::vm::validate_untrusted_wasm; use super::*; use crate::facade::tendermint_proto::google::protobuf; @@ -142,6 +143,9 @@ where || tx_whitelist.contains(&code_hash.to_string().to_lowercase()) || vp_whitelist.contains(&code_hash.to_string().to_lowercase()) { + validate_untrusted_wasm(&code) + .map_err(|e| Error::LoadingWasm(e.to_string()))?; + #[cfg(not(test))] if name.starts_with("tx_") { self.tx_wasm_cache.pre_compile(&code);