Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions tenderlink/src/bandwidth_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -894,8 +894,15 @@ impl ReassemblySlot {
/// returns (success, is_complete)
pub fn insert(&mut self, offset: usize, data: &[u8], is_fin: bool) -> (bool, bool) {

let Some(end_usize) = offset.checked_add(data.len()) else {
return (false, false);
};
if end_usize > MAX_JUMBOGRAM_LEN {
return (false, false);
}

let start = offset as u32;
let end = (offset + data.len()) as u32;
let end = end_usize as u32;

// If this is the final fragment, derive total_len from offset + data.len()
if is_fin {
Expand All @@ -906,7 +913,7 @@ impl ReassemblySlot {
if last_end > end { return (false, false); }
}
self.total_len = Some(end);
self.buf.resize(end as usize, 0);
self.buf.resize(end_usize, 0);
}
}

Expand All @@ -925,8 +932,8 @@ impl ReassemblySlot {
}

// Grow buf if needed (total_len not yet known)
if end as usize > self.buf.len() {
self.buf.resize(end as usize, 0);
if end_usize > self.buf.len() {
self.buf.resize(end_usize, 0);
}

// Find all ranges that overlap or are adjacent to [start, end)
Expand All @@ -946,7 +953,7 @@ impl ReassemblySlot {
}

// Write new data (overlapping parts verified equal)
self.buf[offset..offset + data.len()].copy_from_slice(data);
self.buf[offset..end_usize].copy_from_slice(data);

// Merge: union of [start, end) with all overlapping/adjacent ranges
let merged_start = if first < last { self.received[first].0.min(start) } else { start };
Expand Down Expand Up @@ -1612,7 +1619,11 @@ pub fn new_network_thread(my_keypairs: Vec<IdentityKeyPair>, my_port: u16, max_p
if !success {
existing_connection.unreliable_reassembly[slot_idx] = ReassemblySlot::new();
(success, complete) = existing_connection.unreliable_reassembly[slot_idx].insert(frag_offset as usize, frag_data, is_fin);
assert!(success);
if !success {
if OVERLY_VERBOSE { println!("Error, oversized or invalid jumbogram fragment from {connection_key:?}. Disconnecting..."); }
connections_map.remove(&connection_key);
break 'conn;
}
}
if complete {
let completed = std::mem::replace(&mut existing_connection.unreliable_reassembly[slot_idx], ReassemblySlot::new());
Expand Down
28 changes: 26 additions & 2 deletions tenderlink/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const STP_PACKLET_HDR: usize = 2;
const PATH_MTU: usize = UDP_mMTU
- STP_HEADER_SIZE
- STP_PACKLET_HDR;
const MAX_BFT_PROPOSAL_SIZE: usize = 8 * 1024 * 1024;

// Tweak this!
const MAX_BANDWIDTH_BYTES_PER_SECOND: usize = 1_000_000;
Expand Down Expand Up @@ -716,6 +717,17 @@ impl TMState {
PACKET_TYPE_PROPOSAL_CHUNK => {
let Some(hdr) = PacketProposalChunkHeader::read_from(&mut &signed_data[..])
else { return TMStatus::Fail; };
let proposal_size = hdr.proposal_size as usize;
if proposal_size > MAX_BFT_PROPOSAL_SIZE {
eprintln!("{ctx_str} {ANSI_RED}BFT FAULT{ANSI_RST} at {}.{}.{}: proposal too large ({} bytes). Ignoring...",
height, round, chunk_i, hdr.proposal_size);
return TMStatus::Fail;
}
if chunk_i >= proposal_size.div_ceil(PROPOSAL_CHUNK_DATA_SIZE) {
eprintln!("{ctx_str} {ANSI_RED}BFT FAULT{ANSI_RST} at {}.{}.{}: proposal chunk out of range for {} bytes. Ignoring...",
height, round, chunk_i, hdr.proposal_size);
return TMStatus::Fail;
}

// "have they previously proposed a different value?"
if is_prev_seen_round && round_data.proposal_sigs_n > 0 {
Expand Down Expand Up @@ -1067,7 +1079,7 @@ impl TMState {
// new roster by the decided-block closure).
self.vote_namespace = new_vote_namespace;
self.recent_commit_round_cache.push(self.rounds_data[i].clone());
self.rounds_data.retain(|r| r.height < self.height);
self.rounds_data.retain(|r| r.height >= self.height);
self.locked_value_round = (None, -1);
self.valid_value_round = (None, -1);
self.start_round(roster, now, 0).await;
Expand Down Expand Up @@ -2096,7 +2108,19 @@ pub async fn entry_point(my_root_private_key: SigningKey,
};
let proposal_size = hdr.proposal_size as usize;
let chunk_i = hdr.chunk_i as usize;
let chunk_size = usize::min(PROPOSAL_CHUNK_DATA_SIZE, proposal_size - chunk_i * PROPOSAL_CHUNK_DATA_SIZE);
if proposal_size > MAX_BFT_PROPOSAL_SIZE {
eprintln!("{:05}: couldn't read proposal chunk: proposal too large {}", my_port, proposal_size);
continue;
}
let Some(chunk_o) = chunk_i.checked_mul(PROPOSAL_CHUNK_DATA_SIZE) else {
eprintln!("{:05}: couldn't read proposal chunk: chunk index overflow {}", my_port, chunk_i);
continue;
};
if chunk_o >= proposal_size {
eprintln!("{:05}: couldn't read proposal chunk: chunk index out of range {}", my_port, chunk_i);
continue;
}
let chunk_size = usize::min(PROPOSAL_CHUNK_DATA_SIZE, proposal_size - chunk_o);
let packet_size = chunk_size + PROPOSAL_PACKET_EXTRA;

// NOTE: assume for the moment that this is the valid height, we'll check in the subsequent call
Expand Down