فهرست منبع

zkas: fix out-of-memory panic (#202)

* zkas: fix out-of-memory panic

Fix panic due to unchecked Vec::with_capacity inputs. Also change
VecDeque to use the same validation pattern even though it was not
directly affected

Add panic regression unit test based on fuzzer input that caused the crash

* Add the vec alloc try to async serial as well

---------

Co-authored-by: y <y>
Co-authored-by: parazyd <parazyd@dyne.org>
greptile 2 سال پیش
والد
کامیت
9d5ca4b904
3فایلهای تغییر یافته به همراه21 افزوده شده و 4 حذف شده
  1. 4 2
      src/serial/src/async_lib.rs
  2. 4 2
      src/serial/src/lib.rs
  3. 13 0
      src/zkas/decoder.rs

+ 4 - 2
src/serial/src/async_lib.rs

@@ -544,7 +544,8 @@ impl<T: AsyncDecodable + Send> AsyncDecodable for Vec<T> {
     #[inline]
     async fn decode_async<D: AsyncRead + Unpin + Send>(d: &mut D) -> Result<Self> {
         let len = VarInt::decode_async(d).await?.0;
-        let mut ret = Vec::with_capacity(len as usize);
+        let mut ret = Vec::new();
+        ret.try_reserve(len as usize).map_err(|_| std::io::ErrorKind::InvalidData)?;
         for _ in 0..len {
             ret.push(AsyncDecodable::decode_async(d).await?);
         }
@@ -570,7 +571,8 @@ impl<T: AsyncDecodable + Send> AsyncDecodable for VecDeque<T> {
     #[inline]
     async fn decode_async<D: AsyncRead + Unpin + Send>(d: &mut D) -> Result<Self> {
         let len = VarInt::decode_async(d).await?.0;
-        let mut ret = VecDeque::with_capacity(len as usize);
+        let mut ret = Vec::new();
+        ret.try_reserve(len as usize).map_err(|_| std::io::ErrorKind::InvalidData)?;
         for _ in 0..len {
             ret.push_back(AsyncDecodable::decode_async(d).await?);
         }

+ 4 - 2
src/serial/src/lib.rs

@@ -467,7 +467,8 @@ impl<T: Decodable> Decodable for Vec<T> {
     #[inline]
     fn decode<D: Read>(mut d: D) -> Result<Self, Error> {
         let len = VarInt::decode(&mut d)?.0;
-        let mut ret = Vec::with_capacity(len as usize);
+        let mut ret = Vec::new();
+        ret.try_reserve(len as usize).map_err(|_| std::io::ErrorKind::InvalidData)?;
         for _ in 0..len {
             ret.push(Decodable::decode(&mut d)?);
         }
@@ -491,7 +492,8 @@ impl<T: Decodable> Decodable for VecDeque<T> {
     #[inline]
     fn decode<D: Read>(mut d: D) -> Result<Self, Error> {
         let len = VarInt::decode(&mut d)?.0;
-        let mut ret = VecDeque::with_capacity(len as usize);
+        let mut ret = VecDeque::new();
+        ret.try_reserve(len as usize).map_err(|_| std::io::ErrorKind::InvalidData)?;
         for _ in 0..len {
             ret.push_back(Decodable::decode(&mut d)?);
         }

+ 13 - 0
src/zkas/decoder.rs

@@ -243,3 +243,16 @@ impl ZkBinary {
         Ok(opcodes)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::zkas::ZkBinary;
+
+    #[test]
+    fn panic_regression_001() {
+        // Out-of-memory panic from string deserialization.
+        // Read `doc/src/zkas/bincode.md` to understand the input.
+        let data = vec![11u8, 1, 177, 53, 1, 0, 0, 0, 0, 255, 0, 204, 200, 72, 72, 72, 72, 1];
+        let _dec = ZkBinary::decode(&data);
+    }
+}