Input values are not sanitized after they are deserialized, making it far too easy for Leo to earn SOL (#9706)
* sanitize gossip protocol messages * sanitize transactions * crds protocol sanitize
This commit is contained in:
committed by
GitHub
parent
c372a39dd3
commit
8ef097bf6f
@@ -19,6 +19,7 @@ use crate::{
|
||||
crds_gossip_pull::{CrdsFilter, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS},
|
||||
crds_value::{
|
||||
self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash, Vote,
|
||||
MAX_WALLCLOCK,
|
||||
},
|
||||
epoch_slots::EpochSlots,
|
||||
result::{Error, Result},
|
||||
@@ -28,6 +29,7 @@ use crate::{
|
||||
use rand::distributions::{Distribution, WeightedIndex};
|
||||
use rand::SeedableRng;
|
||||
use rand_chacha::ChaChaRng;
|
||||
use solana_sdk::sanitize::{Sanitize, SanitizeError};
|
||||
|
||||
use bincode::{serialize, serialized_size};
|
||||
use core::cmp;
|
||||
@@ -156,6 +158,15 @@ pub struct PruneData {
|
||||
pub wallclock: u64,
|
||||
}
|
||||
|
||||
impl Sanitize for PruneData {
|
||||
fn sanitize(&self) -> std::result::Result<(), SanitizeError> {
|
||||
if self.wallclock >= MAX_WALLCLOCK {
|
||||
return Err(SanitizeError::ValueOutOfRange);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Signable for PruneData {
|
||||
fn pubkey(&self) -> Pubkey {
|
||||
self.pubkey
|
||||
@@ -212,6 +223,20 @@ enum Protocol {
|
||||
PruneMessage(Pubkey, PruneData),
|
||||
}
|
||||
|
||||
impl Sanitize for Protocol {
|
||||
fn sanitize(&self) -> std::result::Result<(), SanitizeError> {
|
||||
match self {
|
||||
Protocol::PullRequest(filter, val) => {
|
||||
filter.sanitize()?;
|
||||
val.sanitize()
|
||||
}
|
||||
Protocol::PullResponse(_, val) => val.sanitize(),
|
||||
Protocol::PushMessage(_, val) => val.sanitize(),
|
||||
Protocol::PruneMessage(_, val) => val.sanitize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rating for pull requests
|
||||
// A response table is generated as a
|
||||
// 2-d table arranged by target nodes and a
|
||||
@@ -1364,6 +1389,7 @@ impl ClusterInfo {
|
||||
let from_addr = packet.meta.addr();
|
||||
limited_deserialize(&packet.data[..packet.meta.size])
|
||||
.into_iter()
|
||||
.filter(|r: &Protocol| r.sanitize().is_ok())
|
||||
.for_each(|request| match request {
|
||||
Protocol::PullRequest(filter, caller) => {
|
||||
let start = allocated.get();
|
||||
@@ -2791,6 +2817,14 @@ mod tests {
|
||||
assert_eq!(MAX_PROTOCOL_HEADER_SIZE, max_protocol_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_protocol_sanitize() {
|
||||
let mut pd = PruneData::default();
|
||||
pd.wallclock = MAX_WALLCLOCK;
|
||||
let msg = Protocol::PruneMessage(Pubkey::default(), pd);
|
||||
assert_eq!(msg.sanitize(), Err(SanitizeError::ValueOutOfRange));
|
||||
}
|
||||
|
||||
// computes the maximum size for pull request blooms
|
||||
fn max_bloom_size() -> usize {
|
||||
let filter_size = serialized_size(&CrdsFilter::default())
|
||||
|
Reference in New Issue
Block a user