mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-11 18:04:18 +00:00
Limit snappy input stream (#1738)
## Issue Addressed N/A ## Proposed Changes This PR limits the length of the stream received by the snappy decoder to be the maximum allowed size for the received rpc message type. Also adds further checks to ensure that the length specified in the rpc [encoding-dependent header](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/p2p-interface.md#encoding-strategies) is within the bounds for the rpc message type being decoded.
This commit is contained in:
@@ -5,7 +5,7 @@ use crate::rpc::{
|
||||
ssz_snappy::{SSZSnappyInboundCodec, SSZSnappyOutboundCodec},
|
||||
InboundCodec, OutboundCodec,
|
||||
},
|
||||
methods::ResponseTermination,
|
||||
methods::{MaxErrorLen, ResponseTermination, MAX_ERROR_LEN},
|
||||
MaxRequestBlocks, MAX_REQUEST_BLOCKS,
|
||||
};
|
||||
use futures::future::BoxFuture;
|
||||
@@ -51,6 +51,19 @@ lazy_static! {
|
||||
])
|
||||
.as_ssz_bytes()
|
||||
.len();
|
||||
pub static ref ERROR_TYPE_MIN: usize =
|
||||
VariableList::<u8, MaxErrorLen>::from(Vec::<u8>::new())
|
||||
.as_ssz_bytes()
|
||||
.len();
|
||||
pub static ref ERROR_TYPE_MAX: usize =
|
||||
VariableList::<u8, MaxErrorLen>::from(vec![
|
||||
0u8;
|
||||
MAX_ERROR_LEN
|
||||
as usize
|
||||
])
|
||||
.as_ssz_bytes()
|
||||
.len();
|
||||
|
||||
}
|
||||
|
||||
/// The maximum bytes that can be sent across the RPC.
|
||||
@@ -147,6 +160,24 @@ impl<TSpec: EthSpec> UpgradeInfo for RPCProtocol<TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the ssz length bounds for RPC messages.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct RpcLimits {
|
||||
min: usize,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
impl RpcLimits {
|
||||
pub fn new(min: usize, max: usize) -> Self {
|
||||
Self { min, max }
|
||||
}
|
||||
|
||||
/// Returns true if the given length is out of bounds, false otherwise.
|
||||
pub fn is_out_of_bounds(&self, length: usize) -> bool {
|
||||
length > self.max || length < self.min
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks the types in a protocol id.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProtocolId {
|
||||
@@ -163,6 +194,59 @@ pub struct ProtocolId {
|
||||
protocol_id: String,
|
||||
}
|
||||
|
||||
impl ProtocolId {
|
||||
/// Returns min and max size for messages of given protocol id requests.
|
||||
pub fn rpc_request_limits(&self) -> RpcLimits {
|
||||
match self.message_name {
|
||||
Protocol::Status => RpcLimits::new(
|
||||
<StatusMessage as Encode>::ssz_fixed_len(),
|
||||
<StatusMessage as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
Protocol::Goodbye => RpcLimits::new(
|
||||
<GoodbyeReason as Encode>::ssz_fixed_len(),
|
||||
<GoodbyeReason as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
Protocol::BlocksByRange => RpcLimits::new(
|
||||
<BlocksByRangeRequest as Encode>::ssz_fixed_len(),
|
||||
<BlocksByRangeRequest as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
Protocol::BlocksByRoot => {
|
||||
RpcLimits::new(*BLOCKS_BY_ROOT_REQUEST_MIN, *BLOCKS_BY_ROOT_REQUEST_MAX)
|
||||
}
|
||||
Protocol::Ping => RpcLimits::new(
|
||||
<Ping as Encode>::ssz_fixed_len(),
|
||||
<Ping as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
Protocol::MetaData => RpcLimits::new(0, 0), // Metadata requests are empty
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns min and max size for messages of given protocol id responses.
|
||||
pub fn rpc_response_limits<T: EthSpec>(&self) -> RpcLimits {
|
||||
match self.message_name {
|
||||
Protocol::Status => RpcLimits::new(
|
||||
<StatusMessage as Encode>::ssz_fixed_len(),
|
||||
<StatusMessage as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
Protocol::Goodbye => RpcLimits::new(0, 0), // Goodbye request has no response
|
||||
Protocol::BlocksByRange => {
|
||||
RpcLimits::new(*SIGNED_BEACON_BLOCK_MIN, *SIGNED_BEACON_BLOCK_MAX)
|
||||
}
|
||||
Protocol::BlocksByRoot => {
|
||||
RpcLimits::new(*SIGNED_BEACON_BLOCK_MIN, *SIGNED_BEACON_BLOCK_MAX)
|
||||
}
|
||||
Protocol::Ping => RpcLimits::new(
|
||||
<Ping as Encode>::ssz_fixed_len(),
|
||||
<Ping as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
Protocol::MetaData => RpcLimits::new(
|
||||
<MetaData<T> as Encode>::ssz_fixed_len(),
|
||||
<MetaData<T> as Encode>::ssz_fixed_len(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An RPC protocol ID.
|
||||
impl ProtocolId {
|
||||
pub fn new(message_name: Protocol, version: Version, encoding: Encoding) -> Self {
|
||||
@@ -233,7 +317,8 @@ where
|
||||
{
|
||||
Err(e) => Err(RPCError::from(e)),
|
||||
Ok((Some(Ok(request)), stream)) => Ok((request, stream)),
|
||||
Ok((Some(Err(_)), _)) | Ok((None, _)) => Err(RPCError::IncompleteStream),
|
||||
Ok((Some(Err(e)), _)) => Err(e),
|
||||
Ok((None, _)) => Err(RPCError::IncompleteStream),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,7 +470,7 @@ where
|
||||
}
|
||||
|
||||
/// Error in RPC Encoding/Decoding.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RPCError {
|
||||
/// Error when decoding the raw buffer from ssz.
|
||||
// NOTE: in the future a ssz::DecodeError should map to an InvalidData error
|
||||
|
||||
Reference in New Issue
Block a user