From 9c6ad8fbebb4dcb740184cdfc2c63d8f8e4b61dc Mon Sep 17 00:00:00 2001 From: Mauro Lacy Date: Thu, 21 Oct 2021 18:09:15 +0200 Subject: [PATCH] Add protobuf base128 varint decoding --- packages/cw0/src/parse_reply.rs | 48 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/cw0/src/parse_reply.rs b/packages/cw0/src/parse_reply.rs index 91b8501a8..d5f17c41c 100644 --- a/packages/cw0/src/parse_reply.rs +++ b/packages/cw0/src/parse_reply.rs @@ -16,6 +16,37 @@ pub struct MsgExecuteContractResponse { pub data: Option, } +/// Base128 varint decoding. +/// Up to 9 bytes of varints as a practical limit (https://github.com/multiformats/unsigned-varint#practical-maximum-of-9-bytes-for-security) +/// The remaining of the data is kept in the data parameter. +fn parse_protobuf_varint(data: &mut Vec, field_number: u8) -> Result { + let mut len: u64 = 0; + let mut i = 0; + while i < 9 { + if data.len() == i { + return Err(ParseReplyError::ParseFailure(format!( + "failed to decode Protobuf message: field #{}: varint too short", + field_number + ))); + } + len <<= 7; + len += (data[i] & 0x7f) as u64; + if data[i] & 0x80 == 0 { + break; + } + i += 1; + } + if i == 9 { + return Err(ParseReplyError::ParseFailure(format!( + "failed to decode Protobuf message: field #{}: varint too long", + field_number + ))); + } + *data = data.split_off(i + 1); + + Ok(len as usize) // Gently fall back to the arch's max addressable size +} + /// Helper function to parse length-prefixed protobuf fields. /// The remaining of the data is kept in the data parameter. fn parse_protobuf_length_prefixed( @@ -41,24 +72,17 @@ fn parse_protobuf_length_prefixed( field_number, wire_type ))); } - if rest_1.is_empty() { - return Err(ParseReplyError::ParseFailure(format!( - "failed to decode Protobuf message: field #{}: message too short", - field_number - ))); - } - let mut rest_2 = rest_1.split_off(1); - let len = rest_1[0] as usize; - if rest_2.len() < len { + + let len = parse_protobuf_varint(&mut rest_1, field_number)?; + if rest_1.len() < len { return Err(ParseReplyError::ParseFailure(format!( "failed to decode Protobuf message: field #{}: message too short", field_number ))); } - let rest_3 = rest_2.split_off(len); + *data = rest_1.split_off(len); - *data = rest_3; - Ok(rest_2) + Ok(rest_1) } fn parse_protobuf_string(data: &mut Vec, field_number: u8) -> Result {