Skip to content

Commit

Permalink
fix: bignum parsed as Value
Browse files Browse the repository at this point in the history
Fixes: #31

Signed-off-by: Ahmed Charles <[email protected]>
  • Loading branch information
ahmedcharles committed Feb 19, 2024
1 parent d0e5327 commit 81ad8e8
Show file tree
Hide file tree
Showing 3 changed files with 303 additions and 266 deletions.
5 changes: 5 additions & 0 deletions ciborium-ll/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,11 @@ mod tests {
Header::Break,
],
),
("c340", &[Header::Tag(3), Header::Bytes(Some(0))]),
(
"c35fff",
&[Header::Tag(3), Header::Bytes(None), Header::Break],
),
];

for (bytes, headers) in data {
Expand Down
71 changes: 50 additions & 21 deletions ciborium/src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use alloc::{string::String, vec::Vec};

use ciborium_io::Read;
use ciborium_ll::*;
use serde::{de, de::Deserializer as _, forward_to_deserialize_any};
use serde::{
de::{self, value::BytesDeserializer, Deserializer as _},
forward_to_deserialize_any,
};

trait Expected<E: de::Error> {
fn expected(self, kind: &'static str) -> E;
Expand Down Expand Up @@ -72,7 +75,11 @@ where
}

#[inline]
fn integer(&mut self, mut header: Option<Header>) -> Result<(bool, u128), Error<R::Error>> {
fn integer<B: FnMut(u8)>(
&mut self,
mut header: Option<Header>,
mut append: Option<B>,
) -> Result<(bool, u128), Error<R::Error>> {
loop {
let header = match header.take() {
Some(h) => h,
Expand All @@ -99,7 +106,22 @@ where
while let Some(chunk) = segment.pull(&mut buffer)? {
for b in chunk {
match index {
16 => return Err(de::Error::custom("bigint too large")),
16 => {
if let Some(app) = append.as_mut() {
for v in value {
app(v);
}
app(*b);
index = 17; // Indicate overflow, see below
continue;
}
return Err(de::Error::custom("bigint too large"));
}
17 => {
// append is not None
append.as_mut().unwrap()(*b);
continue;
}
0 if *b == 0 => continue, // Skip leading zeros
_ => value[index] = *b,
}
Expand All @@ -109,8 +131,12 @@ where
}
}

value[..index].reverse();
Ok((neg, u128::from_le_bytes(value)))
if index == 17 {
Ok((false, 0))
} else {
value[..index].reverse();
Ok((neg, u128::from_le_bytes(value)))
}
}

h => Err(h.expected("bytes")),
Expand Down Expand Up @@ -157,18 +183,21 @@ where
let header = self.decoder.pull()?;
self.decoder.push(header);

// If it is bytes, capture the length.
let len = match header {
Header::Bytes(x) => x,
_ => None,
};

match (tag, len) {
(tag::BIGPOS, Some(len)) | (tag::BIGNEG, Some(len)) if len <= 16 => {
let result = match self.integer(Some(Header::Tag(tag)))? {
(false, raw) => return visitor.visit_u128(raw),
(true, raw) => i128::try_from(raw).map(|x| x ^ !0),
};
match tag {
tag::BIGPOS | tag::BIGNEG => {
let mut bytes = Vec::new();
let result =
match self.integer(Some(Header::Tag(tag)), Some(|b| bytes.push(b)))? {
(false, _) if !bytes.is_empty() => {
let access = crate::tag::TagAccess::new(
BytesDeserializer::new(&bytes),
Some(tag),
);
return visitor.visit_enum(access);
}
(false, raw) => return visitor.visit_u128(raw),
(true, raw) => i128::try_from(raw).map(|x| x ^ !0),
};

match result {
Ok(x) => visitor.visit_i128(x),
Expand Down Expand Up @@ -238,7 +267,7 @@ where
}

fn deserialize_i64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
let result = match self.integer(None)? {
let result = match self.integer(None, None::<fn(_)>)? {
(false, raw) => i64::try_from(raw),
(true, raw) => i64::try_from(raw).map(|x| x ^ !0),
};
Expand All @@ -250,7 +279,7 @@ where
}

fn deserialize_i128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
let result = match self.integer(None)? {
let result = match self.integer(None, None::<fn(_)>)? {
(false, raw) => i128::try_from(raw),
(true, raw) => i128::try_from(raw).map(|x| x ^ !0),
};
Expand All @@ -274,7 +303,7 @@ where
}

fn deserialize_u64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
let result = match self.integer(None)? {
let result = match self.integer(None, None::<fn(_)>)? {
(false, raw) => u64::try_from(raw),
(true, ..) => return Err(de::Error::custom("unexpected negative integer")),
};
Expand All @@ -286,7 +315,7 @@ where
}

fn deserialize_u128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.integer(None)? {
match self.integer(None, None::<fn(_)>)? {
(false, raw) => visitor.visit_u128(raw),
(true, ..) => Err(de::Error::custom("unexpected negative integer")),
}
Expand Down
Loading

0 comments on commit 81ad8e8

Please sign in to comment.