* Add failing test for decoding ShortU16 alias values (cherry picked from commit338f66f9aa
) * Factor out ShortU16 deser vistor logic to helper (cherry picked from commit6222fbcc66
) * Reimplement decode_len() with ShortU16 vistor helper (cherry picked from commit30dbe257cf
) Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
@ -131,7 +131,8 @@ fn do_get_packet_offsets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read the length of Transaction.signatures (serialized with short_vec)
|
// read the length of Transaction.signatures (serialized with short_vec)
|
||||||
let (sig_len_untrusted, sig_size) = decode_len(&packet.data)?;
|
let (sig_len_untrusted, sig_size) =
|
||||||
|
decode_len(&packet.data).map_err(|_| PacketError::InvalidShortVec)?;
|
||||||
|
|
||||||
// Using msg_start_offset which is based on sig_len_untrusted introduces uncertainty.
|
// Using msg_start_offset which is based on sig_len_untrusted introduces uncertainty.
|
||||||
// Ultimately, the actual sigverify will determine the uncertainty.
|
// Ultimately, the actual sigverify will determine the uncertainty.
|
||||||
@ -156,8 +157,8 @@ fn do_get_packet_offsets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read the length of Message.account_keys (serialized with short_vec)
|
// read the length of Message.account_keys (serialized with short_vec)
|
||||||
let (pubkey_len, pubkey_len_size) =
|
let (pubkey_len, pubkey_len_size) = decode_len(&packet.data[message_account_keys_len_offset..])
|
||||||
decode_len(&packet.data[message_account_keys_len_offset..])?;
|
.map_err(|_| PacketError::InvalidShortVec)?;
|
||||||
|
|
||||||
if (message_account_keys_len_offset + pubkey_len * size_of::<Pubkey>() + pubkey_len_size)
|
if (message_account_keys_len_offset + pubkey_len * size_of::<Pubkey>() + pubkey_len_size)
|
||||||
> packet.meta.size
|
> packet.meta.size
|
||||||
|
@ -38,6 +38,26 @@ impl Serialize for ShortU16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum VisitResult {
|
||||||
|
Done(usize, usize),
|
||||||
|
More(usize, usize),
|
||||||
|
Err,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_byte(elem: u8, len: usize, size: usize) -> VisitResult {
|
||||||
|
let len = len | (elem as usize & 0x7f) << (size * 7);
|
||||||
|
let size = size + 1;
|
||||||
|
let more = elem as usize & 0x80 == 0x80;
|
||||||
|
|
||||||
|
if size > size_of::<u16>() + 1 {
|
||||||
|
VisitResult::Err
|
||||||
|
} else if more {
|
||||||
|
VisitResult::More(len, size)
|
||||||
|
} else {
|
||||||
|
VisitResult::Done(len, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ShortLenVisitor;
|
struct ShortLenVisitor;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for ShortLenVisitor {
|
impl<'de> Visitor<'de> for ShortLenVisitor {
|
||||||
@ -58,15 +78,16 @@ impl<'de> Visitor<'de> for ShortLenVisitor {
|
|||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| de::Error::invalid_length(size, &self))?;
|
.ok_or_else(|| de::Error::invalid_length(size, &self))?;
|
||||||
|
|
||||||
len |= (elem as usize & 0x7f) << (size * 7);
|
match visit_byte(elem, len, size) {
|
||||||
size += 1;
|
VisitResult::Done(l, _) => {
|
||||||
|
len = l;
|
||||||
if elem as usize & 0x80 == 0 {
|
break;
|
||||||
break;
|
}
|
||||||
}
|
VisitResult::More(l, s) => {
|
||||||
|
len = l;
|
||||||
if size > size_of::<u16>() + 1 {
|
size = s;
|
||||||
return Err(de::Error::invalid_length(size, &self));
|
}
|
||||||
|
VisitResult::Err => return Err(de::Error::invalid_length(size + 1, &self)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +199,20 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for ShortVec<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the decoded value and how many bytes it consumed.
|
/// Return the decoded value and how many bytes it consumed.
|
||||||
pub fn decode_len(bytes: &[u8]) -> Result<(usize, usize), Box<bincode::ErrorKind>> {
|
pub fn decode_len(bytes: &[u8]) -> Result<(usize, usize), ()> {
|
||||||
let short_len: ShortU16 = bincode::deserialize(bytes)?;
|
let mut len = 0;
|
||||||
let num_bytes = bincode::serialized_size(&short_len)?;
|
let mut size = 0;
|
||||||
Ok((short_len.0 as usize, num_bytes as usize))
|
for byte in bytes.iter() {
|
||||||
|
match visit_byte(*byte, len, size) {
|
||||||
|
VisitResult::More(l, s) => {
|
||||||
|
len = l;
|
||||||
|
size = s;
|
||||||
|
}
|
||||||
|
VisitResult::Done(len, size) => return Ok((len, size)),
|
||||||
|
VisitResult::Err => return Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -246,4 +277,17 @@ mod tests {
|
|||||||
let s = serde_json::to_string(&vec).unwrap();
|
let s = serde_json::to_string(&vec).unwrap();
|
||||||
assert_eq!(s, "[[3],0,1,2]");
|
assert_eq!(s, "[[3],0,1,2]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_len_aliased_values() {
|
||||||
|
let one1 = [0x01];
|
||||||
|
let one2 = [0x81, 0x00];
|
||||||
|
let one3 = [0x81, 0x80, 0x00];
|
||||||
|
let one4 = [0x81, 0x80, 0x80, 0x00];
|
||||||
|
|
||||||
|
assert_eq!(decode_len(&one1).unwrap(), (1, 1));
|
||||||
|
assert_eq!(decode_len(&one2).unwrap(), (1, 2));
|
||||||
|
assert_eq!(decode_len(&one3).unwrap(), (1, 3));
|
||||||
|
assert!(decode_len(&one4).is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user