From 56aa4cc82892666253481a5933b55f7cfbd909b2 Mon Sep 17 00:00:00 2001 From: Pierre Chifflier Date: Mon, 22 Jan 2024 16:19:24 +0100 Subject: [PATCH] Add new error kind BufferTooSmall, and raise error if buffer capacity is too small (Closes #29) --- assets/err-buffertoosmall.pcapng | Bin 0 -> 10028 bytes src/capture_pcap.rs | 10 +++++++++- src/capture_pcapng.rs | 14 +++++++++++--- src/error.rs | 4 ++++ tests/pcapng.rs | 28 ++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 4 deletions(-) create mode 100755 assets/err-buffertoosmall.pcapng diff --git a/assets/err-buffertoosmall.pcapng b/assets/err-buffertoosmall.pcapng new file mode 100755 index 0000000000000000000000000000000000000000..e677d4acda8d8b46ab23a552bbac462ca4b942ce GIT binary patch literal 10028 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 literal 0 HcmV?d00001 diff --git a/src/capture_pcap.rs b/src/capture_pcap.rs index 2ec0926..2f9b1d2 100644 --- a/src/capture_pcap.rs +++ b/src/capture_pcap.rs @@ -159,7 +159,15 @@ where Err(PcapError::UnexpectedEof) } else { match n { - Needed::Size(n) => Err(PcapError::Incomplete(n.into())), + Needed::Size(n) => { + if self.buffer.available_data() + usize::from(n) + >= self.buffer.capacity() + { + Err(PcapError::BufferTooSmall) + } else { + Err(PcapError::Incomplete(n.into())) + } + } Needed::Unknown => Err(PcapError::Incomplete(0)), } } diff --git a/src/capture_pcapng.rs b/src/capture_pcapng.rs index 0af7182..1b34b64 100644 --- a/src/capture_pcapng.rs +++ b/src/capture_pcapng.rs @@ -5,7 +5,7 @@ use crate::traits::PcapReaderIterator; use circular::Buffer; use nom::combinator::{complete, map}; use nom::multi::many1; -use nom::{IResult, Offset, Needed}; +use nom::{IResult, Needed, Offset}; use std::fmt; use std::io::Read; @@ -179,11 +179,19 @@ where Err(PcapError::UnexpectedEof) } else { match n { - Needed::Size(n) => Err(PcapError::Incomplete(n.into())), + Needed::Size(n) => { + if self.buffer.available_data() + usize::from(n) + >= self.buffer.capacity() + { + Err(PcapError::BufferTooSmall) + } else { + Err(PcapError::Incomplete(n.into())) + } + } Needed::Unknown => Err(PcapError::Incomplete(0)), } } - }, + } } } fn consume(&mut self, offset: usize) { diff --git a/src/error.rs b/src/error.rs index a85f43b..9d6aea5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,6 +6,8 @@ use std::fmt; pub enum PcapError { /// No more data available Eof, + /// Buffer capacity is too small, and some full frame cannot be stored + BufferTooSmall, /// Expected more data but got EOF UnexpectedEof, /// An error happened during a `read` operation @@ -38,6 +40,7 @@ where pub fn to_owned_vec(&self) -> PcapError<&'static [u8]> { match self { PcapError::Eof => PcapError::Eof, + PcapError::BufferTooSmall => PcapError::BufferTooSmall, PcapError::UnexpectedEof => PcapError::UnexpectedEof, PcapError::ReadError => PcapError::ReadError, PcapError::Incomplete(n) => PcapError::Incomplete(*n), @@ -66,6 +69,7 @@ where fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PcapError::Eof => write!(f, "End of file"), + PcapError::BufferTooSmall => write!(f, "Buffer is too small"), PcapError::UnexpectedEof => write!(f, "Unexpected end of file"), PcapError::ReadError => write!(f, "Read error"), PcapError::Incomplete(n) => write!(f, "Incomplete read: {n}"), diff --git a/tests/pcapng.rs b/tests/pcapng.rs index 1abe5ac..34ccbc8 100644 --- a/tests/pcapng.rs +++ b/tests/pcapng.rs @@ -403,3 +403,31 @@ fn err_eof() { let res = parse_block_le(data).expect_err("expected incomplete"); assert!(res.is_incomplete()); } + +// related issue: https://github.com/rusticata/pcap-parser/issues/29 +#[test] +fn test_reader_buffer_too_small() { + let file = File::open("assets/err-buffertoosmall.pcapng").unwrap(); + let mut reader = create_reader(1024, file).expect("PcapNGReader"); + let mut num_blocks = 0; + let mut num_refills = 0; + const MAX_REFILLS: usize = 20; + // the only expected way to exit this loop is to encounter BufferTooSmall + // check number of refills to detect infinite loops + loop { + match reader.next() { + Ok((offset, _block)) => { + num_blocks += 1; + reader.consume(offset) + } + Err(PcapError::Incomplete(_)) => { + num_refills += 1; + assert!(num_refills < MAX_REFILLS); + reader.refill().unwrap(); + } + Err(PcapError::BufferTooSmall) => break, + Err(e) => panic!("Unexpected error {:?}", e), + } + } + assert_eq!(num_blocks, 9); +}