From 8fae92c0cb23dd5fe82a61cf7ad7176cfc616017 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 29 Aug 2023 09:30:09 -0300 Subject: [PATCH] Add instruction limit when decoding XCMs (#1227) * Add instruction limit when decoding XCMs * Make the instruction limit a constant * Use vec for buffer * ".git/.scripts/commands/fmt/fmt.sh" * Go back on std * Use BoundedVec's Decode implementation * ".git/.scripts/commands/fmt/fmt.sh" * Use an actual BoundedVec to decode XCMs * Change comment location * ".git/.scripts/commands/fmt/fmt.sh" * Remove unused imports * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- polkadot/xcm/src/v3/mod.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index 3608679578627..ef3306d276fcb 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -22,14 +22,16 @@ use super::v2::{ }; use crate::{DoubleEncoded, GetWeight}; use alloc::{vec, vec::Vec}; -use bounded_collections::{parameter_types, BoundedVec}; +use bounded_collections::{parameter_types, BoundedVec, ConstU32}; use core::{ convert::{TryFrom, TryInto}, fmt::Debug, result, }; use derivative::Derivative; -use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen}; +use parity_scale_codec::{ + self, Decode, Encode, Error as CodecError, Input as CodecInput, MaxEncodedLen, +}; use scale_info::TypeInfo; mod junction; @@ -60,13 +62,23 @@ pub const VERSION: super::Version = 3; /// An identifier for a query. pub type QueryId = u64; -#[derive(Derivative, Default, Encode, Decode, TypeInfo)] +// TODO (v4): Use `BoundedVec` instead of `Vec` +#[derive(Derivative, Default, Encode, TypeInfo)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] -#[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(Call))] pub struct Xcm(pub Vec>); +const MAX_INSTRUCTIONS_TO_DECODE: u32 = 100; + +impl Decode for Xcm { + fn decode(input: &mut I) -> core::result::Result { + let bounded_instructions = + BoundedVec::, ConstU32>::decode(input)?; + Ok(Self(bounded_instructions.into_inner())) + } +} + impl Xcm { /// Create an empty instance. pub fn new() -> Self { @@ -1426,4 +1438,17 @@ mod tests { let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); assert_eq!(new_xcm, xcm); } + + #[test] + fn decoding_fails_when_too_many_instructions() { + let small_xcm = Xcm::<()>(vec![ClearOrigin; 20]); + let bytes = small_xcm.encode(); + let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]); + assert!(matches!(decoded_xcm, Ok(_))); + + let big_xcm = Xcm::<()>(vec![ClearOrigin; 64_000]); + let bytes = big_xcm.encode(); + let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]); + assert!(matches!(decoded_xcm, Err(CodecError { .. }))); + } }