Sfoglia il codice sorgente

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 anni fa
parent
commit
9d5ca4b904
3 ha cambiato i file con 21 aggiunte e 4 eliminazioni
  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);
+    }
+}