From 412600d4d8c07128537f6fba330a94836714f4e6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 18:54:04 +0300 Subject: [PATCH 01/22] remove unparsed version --- src/elements/mod.rs | 4 ++++ src/elements/section.rs | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 6c1a2cd..2c393a8 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -100,6 +100,8 @@ pub enum Error { InvalidVarUint64, /// Inconsistent metadata InconsistentMetadata, + /// Invalid section id + InvalidSectionId(u8), } impl fmt::Display for Error { @@ -125,6 +127,7 @@ impl fmt::Display for Error { Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"), Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), + Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), } } } @@ -150,6 +153,7 @@ impl error::Error for Error { Error::InvalidVarInt64 => "Not a signed 64-bit integer", Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", Error::InconsistentMetadata => "Inconsistent metadata", + Error::InvalidSectionId(_) => "Invalid section id", } } } diff --git a/src/elements/section.rs b/src/elements/section.rs index 640cdf7..c378e6e 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -2,7 +2,6 @@ use std::io; use super::{ Serialize, Deserialize, - Unparsed, Error, VarUint7, VarUint32, @@ -114,9 +113,9 @@ impl Deserialize for Section { 11 => { Section::Data(DataSection::deserialize(reader)?) }, - _ => { - Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() } - } + invalid_id => { + return Err(Error::InvalidSectionId(invalid_id)) + }, } ) } From 386a96586349beeb09ae630cedabef61fb66bb34 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 19:29:56 +0300 Subject: [PATCH 02/22] fix segment read untrusted --- src/elements/segment.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/elements/segment.rs b/src/elements/segment.rs index e77a6d0..fe5977b 100644 --- a/src/elements/segment.rs +++ b/src/elements/segment.rs @@ -107,10 +107,17 @@ impl Deserialize for DataSegment { fn deserialize(reader: &mut R) -> Result { let index = VarUint32::deserialize(reader)?; let offset = InitExpr::deserialize(reader)?; - let value_len = VarUint32::deserialize(reader)?; + let value_len = u32::from(VarUint32::deserialize(reader)?) as usize; - let mut value_buf = vec![0u8; value_len.into()]; - reader.read_exact(&mut value_buf[..])?; + let mut value_buf = Vec::new(); + let mut total_read = 0; + let mut buf = [0u8; 65536]; + while total_read < value_len { + let next_to_read = if value_len - total_read > 65536 { 65536 } else { value_len - total_read }; + reader.read_exact(&mut buf[0..next_to_read])?; + value_buf.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } Ok(DataSegment { index: index.into(), From 55e0fb852a182bdb2cde89c50794387ca5753e6a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 19:35:11 +0300 Subject: [PATCH 03/22] fix another untrusted allocation --- src/elements/section.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index c378e6e..3d22fe1 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -238,9 +238,17 @@ impl Deserialize for CustomSection { return Ok(CustomSection { name: name, payload: Vec::new() }); } - let payload_left = section_length - total_naming; - let mut payload = vec![0u8; payload_left as usize]; - reader.read_exact(&mut payload[..])?; + let payload_left = section_length as usize - total_naming as usize; + let mut payload = Vec::new(); + + let mut total_read = 0; + let mut buf = [0u8; 65536]; + while total_read < payload_left { + let next_to_read = if payload_left - total_read > 65536 { 65536 } else { payload_left - total_read }; + reader.read_exact(&mut buf[0..next_to_read])?; + payload.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } Ok(CustomSection { name: name, payload: payload }) } From a178efea7e6299be903f8bbba9e3bd800820960f Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 19:42:47 +0300 Subject: [PATCH 04/22] fix 3rd untrusted allcoation --- src/elements/primitives.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index bf65978..c200b23 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -492,11 +492,20 @@ impl Deserialize for String { type Error = Error; fn deserialize(reader: &mut R) -> Result { - let length = VarUint32::deserialize(reader)?.into(); + let length = u32::from(VarUint32::deserialize(reader)?) as usize; if length > 0 { - let mut buf = vec![0u8; length]; - reader.read_exact(&mut buf)?; - String::from_utf8(buf).map_err(|_| Error::NonUtf8String) + let mut str_buf = Vec::new(); + + let mut total_read = 0; + let mut buf = [0u8; 65536]; + while total_read < length { + let next_to_read = if length - total_read > 65536 { 65536 } else { length - total_read }; + reader.read_exact(&mut buf[0..next_to_read])?; + str_buf.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } + + String::from_utf8(str_buf).map_err(|_| Error::NonUtf8String) } else { Ok(String::new()) From 6e89dfbd9e7801840a4caab969284e47e055e6ea Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 20:30:36 +0300 Subject: [PATCH 05/22] take limited amount from reader --- src/elements/section.rs | 102 ++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 41 deletions(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index 3d22fe1..1c9f215 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -293,10 +293,13 @@ impl Deserialize for TypeSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let types: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(TypeSection(types)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + Ok( + TypeSection(CountedList::::deserialize( + &mut reader.by_ref().take(section_length) + )?.into_inner()) + ) } } @@ -355,10 +358,12 @@ impl Deserialize for ImportSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(ImportSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(ImportSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -403,11 +408,12 @@ impl Deserialize for FunctionSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let funcs: Vec = CountedList::::deserialize(reader)? - .into_inner(); - Ok(FunctionSection(funcs)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(FunctionSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -452,10 +458,12 @@ impl Deserialize for TableSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(TableSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(TableSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -500,10 +508,12 @@ impl Deserialize for MemorySection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(MemorySection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(MemorySection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -548,10 +558,12 @@ impl Deserialize for GlobalSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(GlobalSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(GlobalSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -596,10 +608,12 @@ impl Deserialize for ExportSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(ExportSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(ExportSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -644,10 +658,12 @@ impl Deserialize for CodeSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(CodeSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(CodeSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -692,10 +708,12 @@ impl Deserialize for ElementSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(ElementSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(ElementSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } @@ -740,10 +758,12 @@ impl Deserialize for DataSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let _section_length = VarUint32::deserialize(reader)?; - let entries: Vec = CountedList::deserialize(reader)?.into_inner(); - Ok(DataSection(entries)) + use std::io::Read; + let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; + + Ok(DataSection( + CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() + )) } } From 5a2b924e3b858d972245b71e71c12a4325df19ac Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 21:06:09 +0300 Subject: [PATCH 06/22] check for buffer left --- src/elements/mod.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 2c393a8..c273d4b 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -40,10 +40,16 @@ pub use self::name_section::{ LocalNameSection, }; +/// Generic buffer error for deserializing +pub trait BufferError : Sized { + /// Return buffer error instance + fn buffer() -> Self; +} + /// Deserialization from serial i/o pub trait Deserialize : Sized { /// Serialization error produced by deserialization routine. - type Error; + type Error: BufferError; /// Deserialize type from serial i/o fn deserialize(reader: &mut R) -> Result; } @@ -102,6 +108,14 @@ pub enum Error { InconsistentMetadata, /// Invalid section id InvalidSectionId(u8), + /// There is still data left in the buffer + BufferUnderflow, +} + +impl BufferError for Error { + fn buffer() -> Self { + Error::BufferUnderflow + } } impl fmt::Display for Error { @@ -128,6 +142,7 @@ impl fmt::Display for Error { Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), + Error::BufferUnderflow => write!(f, "Buffer underflow"), } } } @@ -154,6 +169,7 @@ impl error::Error for Error { Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", Error::InconsistentMetadata => "Inconsistent metadata", Error::InvalidSectionId(_) => "Invalid section id", + Error::BufferUnderflow => "Buffer underflow", } } } @@ -197,7 +213,11 @@ pub fn deserialize_file>(p: P) -> Result(contents: &[u8]) -> Result { let mut reader = io::Cursor::new(contents); - T::deserialize(&mut reader) + let result = T::deserialize(&mut reader)?; + if reader.position() != contents.len() as u64 { + return Err(T::Error::buffer()) + } + Ok(result) } /// Create buffer with serialized value. From cc0cd414aaa12c32c68727ce677bde5a3a84ffc1 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 15 Feb 2018 23:44:11 +0300 Subject: [PATCH 07/22] add macro for buf read --- src/elements/mod.rs | 2 +- src/elements/primitives.rs | 31 +++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index c273d4b..62be0e3 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -4,9 +4,9 @@ use std::error; use std::fmt; use std::io; +mod primitives; mod module; mod section; -mod primitives; mod types; mod import_entry; mod export_entry; diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index c200b23..b550691 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -2,6 +2,23 @@ use std::io; use byteorder::{LittleEndian, ByteOrder}; use super::{Error, Deserialize, Serialize}; +macro_rules! buffered_read { + ($buffer_size: expr, $length: expr, $reader: expr) => { + { + let mut vec_buf = Vec::new(); + let mut total_read = 0; + let mut buf = [0u8; $buffer_size]; + while total_read < $length { + let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read }; + $reader.read_exact(&mut buf[0..next_to_read])?; + vec_buf.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } + vec_buf + } + } +} + /// Unsigned variable-length integer, limited to 32 bits, /// represented by at most 5 bytes that may contain padding 0x80 bytes. #[derive(Debug, Copy, Clone)] @@ -494,18 +511,7 @@ impl Deserialize for String { fn deserialize(reader: &mut R) -> Result { let length = u32::from(VarUint32::deserialize(reader)?) as usize; if length > 0 { - let mut str_buf = Vec::new(); - - let mut total_read = 0; - let mut buf = [0u8; 65536]; - while total_read < length { - let next_to_read = if length - total_read > 65536 { 65536 } else { length - total_read }; - reader.read_exact(&mut buf[0..next_to_read])?; - str_buf.extend_from_slice(&buf[0..next_to_read]); - total_read += next_to_read; - } - - String::from_utf8(str_buf).map_err(|_| Error::NonUtf8String) + String::from_utf8(buffered_read!(1024, length, reader)).map_err(|_| Error::NonUtf8String) } else { Ok(String::new()) @@ -609,6 +615,7 @@ impl, T: IntoIterator> Serialize f } } + #[cfg(test)] mod tests { From f868b7b3719f442572bc13c07d0b962391494e9d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 00:00:04 +0300 Subject: [PATCH 08/22] fix test payloads --- src/elements/mod.rs | 23 ++++------------------- src/elements/module.rs | 9 --------- src/elements/section.rs | 15 ++++++++------- 3 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 62be0e3..8f7e25e 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -40,16 +40,10 @@ pub use self::name_section::{ LocalNameSection, }; -/// Generic buffer error for deserializing -pub trait BufferError : Sized { - /// Return buffer error instance - fn buffer() -> Self; -} - /// Deserialization from serial i/o pub trait Deserialize : Sized { /// Serialization error produced by deserialization routine. - type Error: BufferError; + type Error: From; /// Deserialize type from serial i/o fn deserialize(reader: &mut R) -> Result; } @@ -57,7 +51,7 @@ pub trait Deserialize : Sized { /// Serialization to serial i/o pub trait Serialize { /// Serialization error produced by serialization routine. - type Error; + type Error: From; /// Serialize type to serial i/o fn serialize(self, writer: &mut W) -> Result<(), Self::Error>; } @@ -108,14 +102,6 @@ pub enum Error { InconsistentMetadata, /// Invalid section id InvalidSectionId(u8), - /// There is still data left in the buffer - BufferUnderflow, -} - -impl BufferError for Error { - fn buffer() -> Self { - Error::BufferUnderflow - } } impl fmt::Display for Error { @@ -142,7 +128,6 @@ impl fmt::Display for Error { Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), - Error::BufferUnderflow => write!(f, "Buffer underflow"), } } } @@ -169,7 +154,6 @@ impl error::Error for Error { Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", Error::InconsistentMetadata => "Inconsistent metadata", Error::InvalidSectionId(_) => "Invalid section id", - Error::BufferUnderflow => "Buffer underflow", } } } @@ -214,8 +198,9 @@ pub fn deserialize_file>(p: P) -> Result(contents: &[u8]) -> Result { let mut reader = io::Cursor::new(contents); let result = T::deserialize(&mut reader)?; + println!("position: {}, content.len: {}", reader.position(), contents.len()); if reader.position() != contents.len() as u64 { - return Err(T::Error::buffer()) + return Err(io::Error::from(io::ErrorKind::InvalidData).into()) } Ok(result) } diff --git a/src/elements/module.rs b/src/elements/module.rs index 1538d50..10ede2e 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -468,15 +468,6 @@ mod integration_tests { assert_eq!(Module::default().magic, module2.magic); } - #[test] - fn inconsistent_meta() { - let result = deserialize_file("./res/cases/v1/payload_len.wasm"); - - // should be error, not panic - if let Err(Error::InconsistentMetadata) = result {} - else { panic!("Should return inconsistent metadata error"); } - } - #[test] fn names() { use super::super::name_section::NameSection; diff --git a/src/elements/section.rs b/src/elements/section.rs index 1c9f215..db0fdcb 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -873,14 +873,14 @@ mod tests { fn types_test_payload() -> &'static [u8] { &[ // section length - 148u8, 0x80, 0x80, 0x80, 0x0, + 11, // 2 functions - 130u8, 0x80, 0x80, 0x80, 0x0, + 2, // func 1, form =1 0x01, // param_count=1 - 129u8, 0x80, 0x80, 0x80, 0x0, + 1, // first param 0x7e, // i64 // no return params @@ -889,7 +889,7 @@ mod tests { // func 2, form=1 0x01, // param_count=1 - 130u8, 0x80, 0x80, 0x80, 0x0, + 2, // first param 0x7e, // second param @@ -925,9 +925,9 @@ mod tests { // section id 0x07, // section length - 148u8, 0x80, 0x80, 0x80, 0x0, + 28, // 6 entries - 134u8, 0x80, 0x80, 0x80, 0x0, + 6, // func "A", index 6 // [name_len(1-5 bytes), name_bytes(name_len, internal_kind(1byte), internal_index(1-5 bytes)]) 0x01, 0x41, 0x01, 0x86, 0x80, 0x00, @@ -1005,10 +1005,11 @@ mod tests { fn data_payload() -> &'static [u8] { &[ 0x0bu8, // section id - 19, // 19 bytes overall + 20, // 19 bytes overall 0x01, // number of segments 0x00, // index 0x0b, // just `end` op + 0x10, // 16x 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From 34344263d56ea358cc79a4ed1bdc1e96f4ba8f3e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 00:24:13 +0300 Subject: [PATCH 09/22] refactor section --- src/elements/mod.rs | 17 +++++++ src/elements/module.rs | 2 +- src/elements/primitives.rs | 17 ------- src/elements/section.rs | 100 +++++++++++-------------------------- 4 files changed, 47 insertions(+), 89 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 8f7e25e..711787f 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -4,6 +4,23 @@ use std::error; use std::fmt; use std::io; +macro_rules! buffered_read { + ($buffer_size: expr, $length: expr, $reader: expr) => { + { + let mut vec_buf = Vec::new(); + let mut total_read = 0; + let mut buf = [0u8; $buffer_size]; + while total_read < $length { + let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read }; + $reader.read_exact(&mut buf[0..next_to_read])?; + vec_buf.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } + vec_buf + } + } +} + mod primitives; mod module; mod section; diff --git a/src/elements/module.rs b/src/elements/module.rs index 10ede2e..93cbda8 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -319,7 +319,7 @@ pub fn peek_size(source: &[u8]) -> usize { #[cfg(test)] mod integration_tests { - use super::super::{deserialize_file, serialize, deserialize_buffer, Section, Error}; + use super::super::{deserialize_file, serialize, deserialize_buffer, Section}; use super::Module; #[test] diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index b550691..3b78299 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -2,23 +2,6 @@ use std::io; use byteorder::{LittleEndian, ByteOrder}; use super::{Error, Deserialize, Serialize}; -macro_rules! buffered_read { - ($buffer_size: expr, $length: expr, $reader: expr) => { - { - let mut vec_buf = Vec::new(); - let mut total_read = 0; - let mut buf = [0u8; $buffer_size]; - while total_read < $length { - let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read }; - $reader.read_exact(&mut buf[0..next_to_read])?; - vec_buf.extend_from_slice(&buf[0..next_to_read]); - total_read += next_to_read; - } - vec_buf - } - } -} - /// Unsigned variable-length integer, limited to 32 bits, /// represented by at most 5 bytes that may contain padding 0x80 bytes. #[derive(Debug, Copy, Clone)] diff --git a/src/elements/section.rs b/src/elements/section.rs index db0fdcb..cc5f525 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -24,6 +24,8 @@ use super::{ use super::types::Type; use super::name_section::NameSection; +const ENTRIES_BUFFER_LENGTH: usize = 16384; + /// Section in the WebAssembly module. #[derive(Debug, Clone)] pub enum Section { @@ -193,6 +195,22 @@ impl Serialize for Section { } } +fn read_entries>( + reader: &mut R, + defined_length: usize, +) -> Result, ::elements::Error> +{ + let inner_buffer = buffered_read!(ENTRIES_BUFFER_LENGTH, defined_length, reader); + Ok(CountedList::::deserialize(&mut io::Cursor::new(inner_buffer))?.into_inner()) +} + +fn read_entries_with_len>(reader: &mut R) + -> Result, ::elements::Error> +{ + let length = u32::from(VarUint32::deserialize(reader)?) as usize; + read_entries(reader, length) +} + /// Custom section #[derive(Debug, Default, Clone)] pub struct CustomSection { @@ -239,16 +257,7 @@ impl Deserialize for CustomSection { } let payload_left = section_length as usize - total_naming as usize; - let mut payload = Vec::new(); - - let mut total_read = 0; - let mut buf = [0u8; 65536]; - while total_read < payload_left { - let next_to_read = if payload_left - total_read > 65536 { 65536 } else { payload_left - total_read }; - reader.read_exact(&mut buf[0..next_to_read])?; - payload.extend_from_slice(&buf[0..next_to_read]); - total_read += next_to_read; - } + let payload = buffered_read!(16384, payload_left, reader); Ok(CustomSection { name: name, payload: payload }) } @@ -293,13 +302,7 @@ impl Deserialize for TypeSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - Ok( - TypeSection(CountedList::::deserialize( - &mut reader.by_ref().take(section_length) - )?.into_inner()) - ) + Ok(TypeSection(read_entries_with_len(reader)?)) } } @@ -358,12 +361,7 @@ impl Deserialize for ImportSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(ImportSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(ImportSection(read_entries_with_len(reader)?)) } } @@ -408,12 +406,7 @@ impl Deserialize for FunctionSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(FunctionSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(FunctionSection(read_entries_with_len(reader)?)) } } @@ -458,12 +451,7 @@ impl Deserialize for TableSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(TableSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(TableSection(read_entries_with_len(reader)?)) } } @@ -508,12 +496,7 @@ impl Deserialize for MemorySection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(MemorySection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(MemorySection(read_entries_with_len(reader)?)) } } @@ -558,12 +541,7 @@ impl Deserialize for GlobalSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(GlobalSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(GlobalSection(read_entries_with_len(reader)?)) } } @@ -608,12 +586,7 @@ impl Deserialize for ExportSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(ExportSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(ExportSection(read_entries_with_len(reader)?)) } } @@ -658,12 +631,7 @@ impl Deserialize for CodeSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(CodeSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(CodeSection(read_entries_with_len(reader)?)) } } @@ -708,12 +676,7 @@ impl Deserialize for ElementSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(ElementSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(ElementSection(read_entries_with_len(reader)?)) } } @@ -758,12 +721,7 @@ impl Deserialize for DataSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - use std::io::Read; - let section_length = u32::from(VarUint32::deserialize(reader)?) as u64; - - Ok(DataSection( - CountedList::::deserialize(&mut reader.by_ref().take(section_length))?.into_inner() - )) + Ok(DataSection(read_entries_with_len(reader)?)) } } From 23119fca953600244d4a367dae4b8606b7c06841 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 00:26:26 +0300 Subject: [PATCH 10/22] remove stray println --- src/elements/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 711787f..8109fcf 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -215,7 +215,6 @@ pub fn deserialize_file>(p: P) -> Result(contents: &[u8]) -> Result { let mut reader = io::Cursor::new(contents); let result = T::deserialize(&mut reader)?; - println!("position: {}, content.len: {}", reader.position(), contents.len()); if reader.position() != contents.len() as u64 { return Err(io::Error::from(io::ErrorKind::InvalidData).into()) } From 8f70a30e15d1d63e5ae74c8725d48306d73a13eb Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 00:54:18 +0300 Subject: [PATCH 11/22] exhaust read for section --- src/elements/section.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index cc5f525..c547efa 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -201,7 +201,14 @@ fn read_entries>( ) -> Result, ::elements::Error> { let inner_buffer = buffered_read!(ENTRIES_BUFFER_LENGTH, defined_length, reader); - Ok(CountedList::::deserialize(&mut io::Cursor::new(inner_buffer))?.into_inner()) + let buf_length = inner_buffer.len(); + let mut cursor = io::Cursor::new(inner_buffer); + let result = Ok(CountedList::::deserialize(&mut cursor)?.into_inner()); + if cursor.position() != buf_length as u64 { + Err(io::Error::from(io::ErrorKind::InvalidData).into()) + } else { + result + } } fn read_entries_with_len>(reader: &mut R) From f890e6d482bf33ee81827f8cd3b1dd4fa6ee9f22 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 01:43:24 +0300 Subject: [PATCH 12/22] fix custom section metering --- src/elements/section.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index c547efa..12725fc 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -252,20 +252,11 @@ impl Deserialize for CustomSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - // todo: maybe use reader.take(section_length) - let section_length: u32 = VarUint32::deserialize(reader)?.into(); - - let name = String::deserialize(reader)?; - let total_naming = name.len() as u32 + name.len() as u32 / 128 + 1; - if total_naming > section_length { - return Err(Error::InconsistentMetadata) - } else if total_naming == section_length { - return Ok(CustomSection { name: name, payload: Vec::new() }); - } - - let payload_left = section_length as usize - total_naming as usize; - let payload = buffered_read!(16384, payload_left, reader); - + let section_length: usize = u32::from(VarUint32::deserialize(reader)?) as usize; + let buf = buffered_read!(16384, section_length, reader); + let mut cursor = ::std::io::Cursor::new(&buf[..]); + let name = String::deserialize(&mut cursor)?; + let payload = buf[cursor.position() as usize..].to_vec(); Ok(CustomSection { name: name, payload: payload }) } } From 5c4e65ae5ee67e15bd9d05a28d7ffecffcd47ef4 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 01:50:10 +0300 Subject: [PATCH 13/22] fix comment --- src/elements/section.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index 12725fc..1ad11cf 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -844,7 +844,7 @@ mod tests { // func 2, form=1 0x01, - // param_count=1 + // param_count=2 2, // first param 0x7e, @@ -961,7 +961,7 @@ mod tests { fn data_payload() -> &'static [u8] { &[ 0x0bu8, // section id - 20, // 19 bytes overall + 20, // 20 bytes overall 0x01, // number of segments 0x00, // index 0x0b, // just `end` op From 196b730bf784f5b2e9afa118d7073b676fc79fa5 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 01:53:03 +0300 Subject: [PATCH 14/22] also segment via macro --- src/elements/segment.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/elements/segment.rs b/src/elements/segment.rs index fe5977b..aa1b1f2 100644 --- a/src/elements/segment.rs +++ b/src/elements/segment.rs @@ -108,16 +108,7 @@ impl Deserialize for DataSegment { let index = VarUint32::deserialize(reader)?; let offset = InitExpr::deserialize(reader)?; let value_len = u32::from(VarUint32::deserialize(reader)?) as usize; - - let mut value_buf = Vec::new(); - let mut total_read = 0; - let mut buf = [0u8; 65536]; - while total_read < value_len { - let next_to_read = if value_len - total_read > 65536 { 65536 } else { value_len - total_read }; - reader.read_exact(&mut buf[0..next_to_read])?; - value_buf.extend_from_slice(&buf[0..next_to_read]); - total_read += next_to_read; - } + let value_buf = buffered_read!(65546, value_len, reader); Ok(DataSegment { index: index.into(), From f3a103e415b6ba6a2823971e3d786fce4286e1de Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 15:11:25 +0300 Subject: [PATCH 15/22] fix sections out of order --- src/elements/mod.rs | 8 ++++++++ src/elements/module.rs | 15 ++++++++++++++- src/elements/section.rs | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 8109fcf..5675d87 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -119,6 +119,10 @@ pub enum Error { InconsistentMetadata, /// Invalid section id InvalidSectionId(u8), + /// Sections are out of order + SectionsOutOfOrder, + /// Duplicated sections + DuplicatedSections(u8), } impl fmt::Display for Error { @@ -145,6 +149,8 @@ impl fmt::Display for Error { Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), + Error::SectionsOutOfOrder => write!(f, "Sections out of order"), + Error::DuplicatedSections(ref id) => write!(f, "Dupliated sections ({})", id), } } } @@ -171,6 +177,8 @@ impl error::Error for Error { Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", Error::InconsistentMetadata => "Inconsistent metadata", Error::InvalidSectionId(_) => "Invalid section id", + Error::SectionsOutOfOrder => "Sections out of order", + Error::DuplicatedSections(_) => "Duplicated section", } } } diff --git a/src/elements/module.rs b/src/elements/module.rs index 93cbda8..44531c5 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -230,11 +230,24 @@ impl Deserialize for Module { return Err(Error::UnsupportedVersion(version)); } + let mut last_section_id = 0; + loop { match Section::deserialize(reader) { Err(Error::UnexpectedEof) => { break; }, Err(e) => { return Err(e) }, - Ok(section) => { sections.push(section); } + Ok(section) => { + println!("Section id: {}", section.id()); + if section.id() != 0 { + if last_section_id > section.id() { + return Err(Error::SectionsOutOfOrder); + } else if last_section_id == section.id() { + return Err(Error::DuplicatedSections(last_section_id)); + } + } + last_section_id = section.id(); + sections.push(section); + } } } diff --git a/src/elements/section.rs b/src/elements/section.rs index 1ad11cf..c2aaa12 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -195,6 +195,27 @@ impl Serialize for Section { } } +impl Section { + pub(crate) fn id(&self) -> u8 { + match *self { + Section::Custom(_) => 0x00, + Section::Unparsed { .. } => 0x00, + Section::Type(_) => 0x1, + Section::Import(_) => 0x2, + Section::Function(_) => 0x3, + Section::Table(_) => 0x4, + Section::Memory(_) => 0x5, + Section::Global(_) => 0x6, + Section::Export(_) => 0x7, + Section::Start(_) => 0x8, + Section::Element(_) => 0x9, + Section::Code(_) => 0x0a, + Section::Data(_) => 0x0b, + Section::Name(_) => 0x00, + } + } +} + fn read_entries>( reader: &mut R, defined_length: usize, From 123b00733f8472454f227f87eb6170e60ac7cd6d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 15:22:34 +0300 Subject: [PATCH 16/22] zeroes check in reserved --- src/elements/mod.rs | 8 ++++++++ src/elements/module.rs | 1 - src/elements/ops.rs | 25 ++++++++++++++++++++----- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 5675d87..d89b076 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -123,6 +123,10 @@ pub enum Error { SectionsOutOfOrder, /// Duplicated sections DuplicatedSections(u8), + /// Invalid memory reference (should be 0) + InvalidMemoryReference(u8), + /// Invalid table reference (should be 0) + InvalidTableReference(u8), } impl fmt::Display for Error { @@ -151,6 +155,8 @@ impl fmt::Display for Error { Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), Error::SectionsOutOfOrder => write!(f, "Sections out of order"), Error::DuplicatedSections(ref id) => write!(f, "Dupliated sections ({})", id), + Error::InvalidMemoryReference(ref mem_ref) => write!(f, "Invalid memory reference ({})", mem_ref), + Error::InvalidTableReference(ref table_ref) => write!(f, "Invalid table reference ({})", table_ref), } } } @@ -179,6 +185,8 @@ impl error::Error for Error { Error::InvalidSectionId(_) => "Invalid section id", Error::SectionsOutOfOrder => "Sections out of order", Error::DuplicatedSections(_) => "Duplicated section", + Error::InvalidMemoryReference(_) => "Invalid memory reference", + Error::InvalidTableReference(_) => "Invalid table reference", } } } diff --git a/src/elements/module.rs b/src/elements/module.rs index 44531c5..394b48c 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -237,7 +237,6 @@ impl Deserialize for Module { Err(Error::UnexpectedEof) => { break; }, Err(e) => { return Err(e) }, Ok(section) => { - println!("Section id: {}", section.id()); if section.id() != 0 { if last_section_id > section.id() { return Err(Error::SectionsOutOfOrder); diff --git a/src/elements/ops.rs b/src/elements/ops.rs index dbfbc67..28c6c40 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -344,9 +344,16 @@ impl Deserialize for Opcode { }, 0x0f => Return, 0x10 => Call(VarUint32::deserialize(reader)?.into()), - 0x11 => CallIndirect( - VarUint32::deserialize(reader)?.into(), - Uint8::deserialize(reader)?.into()), + 0x11 => { + let signature: u32 = VarUint32::deserialize(reader)?.into(); + let table_ref: u8 = Uint8::deserialize(reader)?.into(); + if table_ref != 0 { return Err(Error::InvalidTableReference(table_ref)); } + + CallIndirect( + signature, + table_ref, + ) + }, 0x1a => Drop, 0x1b => Select, @@ -449,8 +456,16 @@ impl Deserialize for Opcode { VarUint32::deserialize(reader)?.into()), - 0x3f => CurrentMemory(Uint8::deserialize(reader)?.into()), - 0x40 => GrowMemory(Uint8::deserialize(reader)?.into()), + 0x3f => { + let mem_ref: u8 = Uint8::deserialize(reader)?.into(); + if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } + CurrentMemory(mem_ref) + }, + 0x40 => { + let mem_ref: u8 = Uint8::deserialize(reader)?.into(); + if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } + GrowMemory(mem_ref) + } 0x41 => I32Const(VarInt32::deserialize(reader)?.into()), 0x42 => I64Const(VarInt64::deserialize(reader)?.into()), From 43eec3a97fd9daab5d6c6494af9e2f794a5aff3d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 15:30:05 +0300 Subject: [PATCH 17/22] fix typo in integer --- src/elements/segment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/segment.rs b/src/elements/segment.rs index aa1b1f2..1fe49c5 100644 --- a/src/elements/segment.rs +++ b/src/elements/segment.rs @@ -108,7 +108,7 @@ impl Deserialize for DataSegment { let index = VarUint32::deserialize(reader)?; let offset = InitExpr::deserialize(reader)?; let value_len = u32::from(VarUint32::deserialize(reader)?) as usize; - let value_buf = buffered_read!(65546, value_len, reader); + let value_buf = buffered_read!(65536, value_len, reader); Ok(DataSegment { index: index.into(), From 3dd4289b4c0842361da4556ef1a86b54612b788e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 16 Feb 2018 16:47:10 +0300 Subject: [PATCH 18/22] add doc comment --- src/elements/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index d89b076..ec8dd9e 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -65,7 +65,8 @@ pub trait Deserialize : Sized { fn deserialize(reader: &mut R) -> Result; } -/// Serialization to serial i/o +/// Serialization to serial i/o. Takes self by value to consume less memory +/// (parity-wasm IR is being partially freed by filling the result buffer). pub trait Serialize { /// Serialization error produced by serialization routine. type Error: From; From fb00111048f88ee289533788bc2fd05b08aad815 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 18 Feb 2018 21:21:08 +0300 Subject: [PATCH 19/22] strict function form --- src/elements/mod.rs | 4 ++++ src/elements/section.rs | 4 ++-- src/elements/types.rs | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/elements/mod.rs b/src/elements/mod.rs index ec8dd9e..0b7d1e4 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -128,6 +128,8 @@ pub enum Error { InvalidMemoryReference(u8), /// Invalid table reference (should be 0) InvalidTableReference(u8), + /// Unknown function form (should be 0x60) + UnknownFunctionForm(u8), } impl fmt::Display for Error { @@ -158,6 +160,7 @@ impl fmt::Display for Error { Error::DuplicatedSections(ref id) => write!(f, "Dupliated sections ({})", id), Error::InvalidMemoryReference(ref mem_ref) => write!(f, "Invalid memory reference ({})", mem_ref), Error::InvalidTableReference(ref table_ref) => write!(f, "Invalid table reference ({})", table_ref), + Error::UnknownFunctionForm(ref form) => write!(f, "Unknown function form ({})", form), } } } @@ -188,6 +191,7 @@ impl error::Error for Error { Error::DuplicatedSections(_) => "Duplicated section", Error::InvalidMemoryReference(_) => "Invalid memory reference", Error::InvalidTableReference(_) => "Invalid table reference", + Error::UnknownFunctionForm(_) => "Unknown function form", } } } diff --git a/src/elements/section.rs b/src/elements/section.rs index c2aaa12..ebc7588 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -855,7 +855,7 @@ mod tests { // 2 functions 2, // func 1, form =1 - 0x01, + 0x60, // param_count=1 1, // first param @@ -864,7 +864,7 @@ mod tests { 0x00, // func 2, form=1 - 0x01, + 0x60, // param_count=2 2, // first param diff --git a/src/elements/types.rs b/src/elements/types.rs index 9e82767..11fedcc 100644 --- a/src/elements/types.rs +++ b/src/elements/types.rs @@ -171,6 +171,10 @@ impl Deserialize for FunctionType { fn deserialize(reader: &mut R) -> Result { let form: u8 = VarUint7::deserialize(reader)?.into(); + if form != 0x60 { + return Err(Error::UnknownFunctionForm(form)); + } + let params: Vec = CountedList::deserialize(reader)?.into_inner(); let has_return_type = VarUint1::deserialize(reader)?; From cd3ab4017be2dbf41b9c212ab7b96f0d572be50a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 18 Feb 2018 21:33:48 +0300 Subject: [PATCH 20/22] also limit start section --- src/elements/section.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index ebc7588..7329fb2 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -103,8 +103,16 @@ impl Deserialize for Section { Section::Export(ExportSection::deserialize(reader)?) }, 8 => { - let _section_length = VarUint32::deserialize(reader)?; - Section::Start(VarUint32::deserialize(reader)?.into()) + let section_length = u32::from(VarUint32::deserialize(reader)?) as usize; + let inner_buffer = buffered_read!(256, section_length, reader); + let buf_length = inner_buffer.len(); + let mut cursor = io::Cursor::new(inner_buffer); + let result = Section::Start(VarUint32::deserialize(&mut cursor)?.into()); + if cursor.position() != buf_length as u64 { + return Err(io::Error::from(io::ErrorKind::InvalidData).into()); + } else { + result + } }, 9 => { Section::Element(ElementSection::deserialize(reader)?) From 3e5d6e1017ea4f920c1e492ad34789a803d4e700 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 18 Feb 2018 22:00:37 +0300 Subject: [PATCH 21/22] also use section reader for funcs body --- src/elements/func.rs | 8 ++++--- src/elements/section.rs | 52 ++++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/elements/func.rs b/src/elements/func.rs index 4aa3bbc..91f9feb 100644 --- a/src/elements/func.rs +++ b/src/elements/func.rs @@ -3,6 +3,7 @@ use super::{ Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes, Serialize, CountedWriter, CountedListWriter, }; +use elements::section::SectionReader; /// Function signature (type reference) #[derive(Debug, Copy, Clone)] @@ -116,9 +117,10 @@ impl Deserialize for FuncBody { fn deserialize(reader: &mut R) -> Result { // todo: maybe use reader.take(section_length) - let _body_size = VarUint32::deserialize(reader)?; - let locals: Vec = CountedList::deserialize(reader)?.into_inner(); - let opcodes = Opcodes::deserialize(reader)?; + let mut body_reader = SectionReader::new(reader)?; + let locals: Vec = CountedList::::deserialize(&mut body_reader)?.into_inner(); + let opcodes = Opcodes::deserialize(&mut body_reader)?; + body_reader.close()?; Ok(FuncBody { locals: locals, opcodes: opcodes }) } } diff --git a/src/elements/section.rs b/src/elements/section.rs index 7329fb2..bf713c8 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -103,16 +103,10 @@ impl Deserialize for Section { Section::Export(ExportSection::deserialize(reader)?) }, 8 => { - let section_length = u32::from(VarUint32::deserialize(reader)?) as usize; - let inner_buffer = buffered_read!(256, section_length, reader); - let buf_length = inner_buffer.len(); - let mut cursor = io::Cursor::new(inner_buffer); - let result = Section::Start(VarUint32::deserialize(&mut cursor)?.into()); - if cursor.position() != buf_length as u64 { - return Err(io::Error::from(io::ErrorKind::InvalidData).into()); - } else { - result - } + let mut section_reader = SectionReader::new(reader)?; + let start_idx = VarUint32::deserialize(&mut section_reader)?; + section_reader.close()?; + Section::Start(start_idx.into()) }, 9 => { Section::Element(ElementSection::deserialize(reader)?) @@ -240,7 +234,43 @@ fn read_entries>( } } -fn read_entries_with_len>(reader: &mut R) +pub(crate) struct SectionReader { + cursor: io::Cursor>, + declared_length: usize, +} + +impl SectionReader { + pub fn new(reader: &mut R) -> Result { + let length = u32::from(VarUint32::deserialize(reader)?) as usize; + let inner_buffer = buffered_read!(ENTRIES_BUFFER_LENGTH, length, reader); + let buf_length = inner_buffer.len(); + let cursor = io::Cursor::new(inner_buffer); + + Ok(SectionReader { + cursor: cursor, + declared_length: buf_length, + }) + } + + pub fn close(self) -> Result<(), ::elements::Error> { + let cursor = self.cursor; + let buf_length = self.declared_length; + + if cursor.position() != buf_length as u64 { + Err(io::Error::from(io::ErrorKind::InvalidData).into()) + } else { + Ok(()) + } + } +} + +impl io::Read for SectionReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.cursor.read(buf) + } +} + +pub (crate) fn read_entries_with_len>(reader: &mut R) -> Result, ::elements::Error> { let length = u32::from(VarUint32::deserialize(reader)?) as usize; From 7cf8a7a16b154452b64bc1cee290ea1875bd2f90 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 18 Feb 2018 22:08:12 +0300 Subject: [PATCH 22/22] simplify section reader --- src/elements/section.rs | 44 ++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/elements/section.rs b/src/elements/section.rs index bf713c8..98fa451 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -218,22 +218,6 @@ impl Section { } } -fn read_entries>( - reader: &mut R, - defined_length: usize, -) -> Result, ::elements::Error> -{ - let inner_buffer = buffered_read!(ENTRIES_BUFFER_LENGTH, defined_length, reader); - let buf_length = inner_buffer.len(); - let mut cursor = io::Cursor::new(inner_buffer); - let result = Ok(CountedList::::deserialize(&mut cursor)?.into_inner()); - if cursor.position() != buf_length as u64 { - Err(io::Error::from(io::ErrorKind::InvalidData).into()) - } else { - result - } -} - pub(crate) struct SectionReader { cursor: io::Cursor>, declared_length: usize, @@ -270,11 +254,13 @@ impl io::Read for SectionReader { } } -pub (crate) fn read_entries_with_len>(reader: &mut R) +fn read_entries>(reader: &mut R) -> Result, ::elements::Error> { - let length = u32::from(VarUint32::deserialize(reader)?) as usize; - read_entries(reader, length) + let mut section_reader = SectionReader::new(reader)?; + let result = CountedList::::deserialize(&mut section_reader)?.into_inner(); + section_reader.close()?; + Ok(result) } /// Custom section @@ -359,7 +345,7 @@ impl Deserialize for TypeSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(TypeSection(read_entries_with_len(reader)?)) + Ok(TypeSection(read_entries(reader)?)) } } @@ -418,7 +404,7 @@ impl Deserialize for ImportSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(ImportSection(read_entries_with_len(reader)?)) + Ok(ImportSection(read_entries(reader)?)) } } @@ -463,7 +449,7 @@ impl Deserialize for FunctionSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(FunctionSection(read_entries_with_len(reader)?)) + Ok(FunctionSection(read_entries(reader)?)) } } @@ -508,7 +494,7 @@ impl Deserialize for TableSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(TableSection(read_entries_with_len(reader)?)) + Ok(TableSection(read_entries(reader)?)) } } @@ -553,7 +539,7 @@ impl Deserialize for MemorySection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(MemorySection(read_entries_with_len(reader)?)) + Ok(MemorySection(read_entries(reader)?)) } } @@ -598,7 +584,7 @@ impl Deserialize for GlobalSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(GlobalSection(read_entries_with_len(reader)?)) + Ok(GlobalSection(read_entries(reader)?)) } } @@ -643,7 +629,7 @@ impl Deserialize for ExportSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(ExportSection(read_entries_with_len(reader)?)) + Ok(ExportSection(read_entries(reader)?)) } } @@ -688,7 +674,7 @@ impl Deserialize for CodeSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(CodeSection(read_entries_with_len(reader)?)) + Ok(CodeSection(read_entries(reader)?)) } } @@ -733,7 +719,7 @@ impl Deserialize for ElementSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(ElementSection(read_entries_with_len(reader)?)) + Ok(ElementSection(read_entries(reader)?)) } } @@ -778,7 +764,7 @@ impl Deserialize for DataSection { type Error = Error; fn deserialize(reader: &mut R) -> Result { - Ok(DataSection(read_entries_with_len(reader)?)) + Ok(DataSection(read_entries(reader)?)) } }