Nits for sanitize trait (bp #9741) (#9809)

* thiserror, docs, remove general Failure case (#9741)

automerge

(cherry picked from commit a0514eb2ae)

# Conflicts:
#	core/src/crds_value.rs
#	core/src/epoch_slots.rs
#	sdk/src/sanitize.rs

* rebase

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
mergify[bot]
2020-04-30 14:35:18 -07:00
committed by GitHub
parent c63bd05458
commit 5bc57ea004
7 changed files with 46 additions and 17 deletions

View File

@ -157,7 +157,7 @@ pub struct PruneData {
impl Sanitize for PruneData { impl Sanitize for PruneData {
fn sanitize(&self) -> std::result::Result<(), SanitizeError> { fn sanitize(&self) -> std::result::Result<(), SanitizeError> {
if self.wallclock >= MAX_WALLCLOCK { if self.wallclock >= MAX_WALLCLOCK {
return Err(SanitizeError::ValueOutOfRange); return Err(SanitizeError::ValueOutOfBounds);
} }
Ok(()) Ok(())
} }
@ -2641,7 +2641,7 @@ mod tests {
let mut pd = PruneData::default(); let mut pd = PruneData::default();
pd.wallclock = MAX_WALLCLOCK; pd.wallclock = MAX_WALLCLOCK;
let msg = Protocol::PruneMessage(Pubkey::default(), pd); let msg = Protocol::PruneMessage(Pubkey::default(), pd);
assert_eq!(msg.sanitize(), Err(SanitizeError::ValueOutOfRange)); assert_eq!(msg.sanitize(), Err(SanitizeError::ValueOutOfBounds));
} }
// computes the maximum size for pull request blooms // computes the maximum size for pull request blooms

View File

@ -42,7 +42,7 @@ pub struct ContactInfo {
impl Sanitize for ContactInfo { impl Sanitize for ContactInfo {
fn sanitize(&self) -> std::result::Result<(), SanitizeError> { fn sanitize(&self) -> std::result::Result<(), SanitizeError> {
if self.wallclock >= MAX_WALLCLOCK { if self.wallclock >= MAX_WALLCLOCK {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
Ok(()) Ok(())
} }
@ -325,4 +325,12 @@ mod tests {
ci.rpc = socketaddr!("127.0.0.1:234"); ci.rpc = socketaddr!("127.0.0.1:234");
assert!(ci.valid_client_facing_addr().is_some()); assert!(ci.valid_client_facing_addr().is_some());
} }
#[test]
fn test_sanitize() {
let mut ci = ContactInfo::default();
assert_eq!(ci.sanitize(), Ok(()));
ci.wallclock = MAX_WALLCLOCK;
assert_eq!(ci.sanitize(), Err(SanitizeError::ValueOutOfBounds));
}
} }

View File

@ -96,7 +96,7 @@ pub struct EpochIncompleteSlots {
impl Sanitize for EpochIncompleteSlots { impl Sanitize for EpochIncompleteSlots {
fn sanitize(&self) -> Result<(), SanitizeError> { fn sanitize(&self) -> Result<(), SanitizeError> {
if self.first >= MAX_SLOT { if self.first >= MAX_SLOT {
return Err(SanitizeError::Failed); return Err(SanitizeError::InvalidValue);
} }
//rest of the data doesn't matter since we no longer decompress //rest of the data doesn't matter since we no longer decompress
//these values //these values
@ -110,7 +110,7 @@ impl Sanitize for CrdsData {
CrdsData::ContactInfo(val) => val.sanitize(), CrdsData::ContactInfo(val) => val.sanitize(),
CrdsData::Vote(ix, val) => { CrdsData::Vote(ix, val) => {
if *ix >= MAX_VOTES { if *ix >= MAX_VOTES {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
val.sanitize() val.sanitize()
} }
@ -118,7 +118,7 @@ impl Sanitize for CrdsData {
CrdsData::AccountsHashes(val) => val.sanitize(), CrdsData::AccountsHashes(val) => val.sanitize(),
CrdsData::EpochSlots(ix, val) => { CrdsData::EpochSlots(ix, val) => {
if *ix as usize >= MAX_EPOCH_SLOTS as usize { if *ix as usize >= MAX_EPOCH_SLOTS as usize {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
val.sanitize() val.sanitize()
} }
@ -136,11 +136,11 @@ pub struct SnapshotHash {
impl Sanitize for SnapshotHash { impl Sanitize for SnapshotHash {
fn sanitize(&self) -> Result<(), SanitizeError> { fn sanitize(&self) -> Result<(), SanitizeError> {
if self.wallclock >= MAX_WALLCLOCK { if self.wallclock >= MAX_WALLCLOCK {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
for (slot, _) in &self.hashes { for (slot, _) in &self.hashes {
if *slot >= MAX_SLOT { if *slot >= MAX_SLOT {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
} }
self.from.sanitize() self.from.sanitize()
@ -183,17 +183,17 @@ impl EpochSlots {
impl Sanitize for EpochSlots { impl Sanitize for EpochSlots {
fn sanitize(&self) -> Result<(), SanitizeError> { fn sanitize(&self) -> Result<(), SanitizeError> {
if self.wallclock >= MAX_WALLCLOCK { if self.wallclock >= MAX_WALLCLOCK {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
if self.lowest >= MAX_SLOT { if self.lowest >= MAX_SLOT {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
if self.root >= MAX_SLOT { if self.root >= MAX_SLOT {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
for slot in &self.slots { for slot in &self.slots {
if *slot >= MAX_SLOT { if *slot >= MAX_SLOT {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
} }
self.stash.sanitize()?; self.stash.sanitize()?;
@ -211,7 +211,7 @@ pub struct Vote {
impl Sanitize for Vote { impl Sanitize for Vote {
fn sanitize(&self) -> Result<(), SanitizeError> { fn sanitize(&self) -> Result<(), SanitizeError> {
if self.wallclock >= MAX_WALLCLOCK { if self.wallclock >= MAX_WALLCLOCK {
return Err(SanitizeError::Failed); return Err(SanitizeError::ValueOutOfBounds);
} }
self.from.sanitize()?; self.from.sanitize()?;
self.transaction.sanitize() self.transaction.sanitize()
@ -484,7 +484,7 @@ mod test {
), ),
&keypair, &keypair,
); );
assert!(item.sanitize().is_err()); assert_eq!(item.sanitize(), Err(SanitizeError::ValueOutOfBounds));
} }
#[test] #[test]
fn test_compute_vote_index_empty() { fn test_compute_vote_index_empty() {

View File

@ -1,5 +1,6 @@
//! The `hash` module provides functions for creating SHA-256 hashes. //! The `hash` module provides functions for creating SHA-256 hashes.
use crate::sanitize::Sanitize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{convert::TryFrom, fmt, mem, str::FromStr}; use std::{convert::TryFrom, fmt, mem, str::FromStr};
use thiserror::Error; use thiserror::Error;
@ -30,6 +31,8 @@ impl Hasher {
} }
} }
impl Sanitize for Hash {}
impl AsRef<[u8]> for Hash { impl AsRef<[u8]> for Hash {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
&self.0[..] &self.0[..]

View File

@ -1,5 +1,6 @@
//! Defines a composable Instruction type and a memory-efficient CompiledInstruction. //! Defines a composable Instruction type and a memory-efficient CompiledInstruction.
use crate::sanitize::Sanitize;
use crate::{pubkey::Pubkey, short_vec, system_instruction::SystemError}; use crate::{pubkey::Pubkey, short_vec, system_instruction::SystemError};
use bincode::serialize; use bincode::serialize;
use serde::Serialize; use serde::Serialize;
@ -216,6 +217,8 @@ pub struct CompiledInstruction {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
impl Sanitize for CompiledInstruction {}
impl CompiledInstruction { impl CompiledInstruction {
pub fn new<T: Serialize>(program_ids_index: u8, data: &T, accounts: Vec<u8>) -> Self { pub fn new<T: Serialize>(program_ids_index: u8, data: &T, accounts: Vec<u8>) -> Self {
let data = serialize(data).unwrap(); let data = serialize(data).unwrap();

View File

@ -184,6 +184,9 @@ impl Sanitize for Message {
} }
} }
} }
self.account_keys.sanitize()?;
self.recent_blockhash.sanitize()?;
self.instructions.sanitize()?;
Ok(()) Ok(())
} }
} }

View File

@ -1,10 +1,22 @@
#[derive(PartialEq, Debug)] use thiserror::Error;
#[derive(PartialEq, Debug, Error, Eq, Clone)]
pub enum SanitizeError { pub enum SanitizeError {
Failed, #[error("index out of bounds")]
IndexOutOfBounds, IndexOutOfBounds,
ValueOutOfRange, #[error("value out of bounds")]
ValueOutOfBounds,
#[error("invalid value")]
InvalidValue,
} }
/// Trait for sanitizing values and members of over the wire messages.
/// Implementation should recursively decent through the data structure
/// and sanitize all struct members and enum clauses. Sanitize excludes
/// signature verification checks, those are handled by another pass.
/// Sanitize checks should include but are not limited too:
/// * All index values are in range
/// * All values are within their static max/min bounds
pub trait Sanitize { pub trait Sanitize {
fn sanitize(&self) -> Result<(), SanitizeError> { fn sanitize(&self) -> Result<(), SanitizeError> {
Ok(()) Ok(())