protocol: Fix panic when serializing large frames

In 3c5668edd2 I mistakenly moved the check
the length of an encoded `wire::Message` from its `impl wire::Encode` to
the `fn serialize`, so that it would not apply only to messages (as
originally intended), but to *any* argument of `serialize`.

This is not a problem for gossip messages, but catastrophic for Git
streams, which tend to send a lot of data.

The fix is simple: Move the check back into `impl Encode for Message`.
This commit is contained in:
Lorenz Leutgeb 2025-08-20 15:34:02 +02:00 committed by Fintan Halpenny
parent c5b99db101
commit a8426dfdac
3 changed files with 25 additions and 6 deletions

View File

@ -103,14 +103,10 @@ pub trait Decode: Sized {
} }
/// Encode an object into a byte vector. /// Encode an object into a byte vector.
///
/// # Panics
///
/// If the encoded object exceeds [`Size::MAX`].
pub fn serialize<E: Encode + ?Sized>(data: &E) -> Vec<u8> { pub fn serialize<E: Encode + ?Sized>(data: &E) -> Vec<u8> {
let mut buffer = Vec::new().limit(Size::MAX as usize); let mut buffer = Vec::new();
data.encode(&mut buffer); data.encode(&mut buffer);
buffer.into_inner() buffer
} }
/// Decode an object from a slice. /// Decode an object from a slice.

View File

@ -390,4 +390,25 @@ mod test {
assert_eq!(StreamId::control(Link::Inbound), StreamId(VarInt(0b001))); assert_eq!(StreamId::control(Link::Inbound), StreamId(VarInt(0b001)));
assert_eq!(StreamId::gossip(Link::Inbound), StreamId(VarInt(0b011))); assert_eq!(StreamId::gossip(Link::Inbound), StreamId(VarInt(0b011)));
} }
#[test]
fn test_encode_git_large() {
let size = u16::MAX as usize * 3;
assert!(
size > (wire::Size::MAX as usize * 2),
"we want to test sizes that are way larger than any gossip message"
);
let a_lot_of_data = vec![0u8; size];
let frame: Frame<Message> = Frame::git(StreamId(0u8.into()), a_lot_of_data);
// In previous versions since 3c5668e this would panic.
let bytes = wire::serialize(&frame);
assert!(
bytes.len() > wire::Size::MAX as usize * 2,
"just making sure that whatever was encoded is still quite large"
);
}
} }

View File

@ -234,6 +234,8 @@ impl wire::Decode for Info {
impl wire::Encode for Message { impl wire::Encode for Message {
fn encode(&self, buf: &mut impl BufMut) { fn encode(&self, buf: &mut impl BufMut) {
let buf = &mut buf.limit(wire::Size::MAX as usize);
self.type_id().encode(buf); self.type_id().encode(buf);
match self { match self {