diff --git a/CHANGELOG.md b/CHANGELOG.md index 481c007bc..4852d25d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,12 +53,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - When skipping invalid frames in `ParsingMode::{BestAttempt, Relaxed}`, the parser will no longer be able to go out of the bounds of the frame content ([issue](https://github.com/Serial-ATA/lofty-rs/issues/458)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/459)) - **MP4**: Support for flag items (ex. `cpil`) of any size (not just 1 byte) ([issue](https://github.com/Serial-ATA/lofty-rs/issues/457)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/460)) -- **Fuzzing** (Thanks [@qarmin](https://github.com/qarmin)!) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/476)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/479)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/483)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/489)): +- **Fuzzing** (Thanks [@qarmin](https://github.com/qarmin)!) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/476)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/479)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/483)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/489)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/496)): - **MusePack**: Fix panic when ID3v2 tag sizes exceed the stream length ([issue](https://github.com/Serial-ATA/lofty-rs/issues/470)) - **WAV**: Fix panic when calculating bit depth with abnormally large `bytes_per_sample` ([issue](https://github.com/Serial-ATA/lofty-rs/issues/471)) - **WavPack***: Fix panic when encountering wrongly sized blocks ([issue](https://github.com/Serial-ATA/lofty-rs/issues/472)) ([issue](https://github.com/Serial-ATA/lofty-rs/issues/480)) - **WavPack***: Fix panic when encountering zero-sized blocks ([issue](https://github.com/Serial-ATA/lofty-rs/issues/473)) - **WavPack**: Verify the size of non-standard sample rate blocks ([issue](https://github.com/Serial-ATA/lofty-rs/issues/488)) + - **WavPack**: Fix potential overflow in bit depth calculation ([issue](https://github.com/Serial-ATA/lofty-rs/issues/491)) - **MPEG**: Fix panic when APE tags are incorrectly sized ([issue](https://github.com/Serial-ATA/lofty-rs/issues/474)) - **MPEG**: Fix panic when calculating the stream length for files with improperly sized frames ([issue](https://github.com/Serial-ATA/lofty-rs/issues/487)) - **ID3v2**: Fix panic when parsing non-ASCII `TDAT` and `TIME` frames in `TDRC` conversion ([issue](https://github.com/Serial-ATA/lofty-rs/issues/477)) diff --git a/lofty/src/id3/v1/tag.rs b/lofty/src/id3/v1/tag.rs index 2d91c3939..3e78ec944 100644 --- a/lofty/src/id3/v1/tag.rs +++ b/lofty/src/id3/v1/tag.rs @@ -424,7 +424,7 @@ impl<'a> Into> for &'a Tag { } } -impl<'a> Id3v1TagRef<'a> { +impl Id3v1TagRef<'_> { pub(super) fn is_empty(&self) -> bool { self.title.is_none() && self.artist.is_none() diff --git a/lofty/src/id3/v2/frame/mod.rs b/lofty/src/id3/v2/frame/mod.rs index a06078b5e..787eaec6f 100644 --- a/lofty/src/id3/v2/frame/mod.rs +++ b/lofty/src/id3/v2/frame/mod.rs @@ -164,7 +164,7 @@ impl<'a> Frame<'a> { } } -impl<'a> Frame<'a> { +impl Frame<'_> { /// Check for empty content /// /// Returns `None` if the frame type is not supported. @@ -194,7 +194,7 @@ impl<'a> Frame<'a> { } } -impl<'a> Frame<'a> { +impl Frame<'_> { pub(super) fn as_bytes(&self, is_id3v23: bool) -> Result> { Ok(match self { Frame::Comment(comment) => comment.as_bytes(is_id3v23)?, diff --git a/lofty/src/id3/v2/frame/read.rs b/lofty/src/id3/v2/frame/read.rs index b415496bb..74185d2a4 100644 --- a/lofty/src/id3/v2/frame/read.rs +++ b/lofty/src/id3/v2/frame/read.rs @@ -19,7 +19,7 @@ pub(crate) enum ParsedFrame<'a> { Eof, } -impl<'a> ParsedFrame<'a> { +impl ParsedFrame<'_> { pub(crate) fn read( reader: &mut R, version: Id3v2Version, diff --git a/lofty/src/id3/v2/items/attached_picture_frame.rs b/lofty/src/id3/v2/items/attached_picture_frame.rs index 79ecfb55a..027cae486 100644 --- a/lofty/src/id3/v2/items/attached_picture_frame.rs +++ b/lofty/src/id3/v2/items/attached_picture_frame.rs @@ -24,7 +24,7 @@ pub struct AttachedPictureFrame<'a> { pub picture: Picture, } -impl<'a> AttachedPictureFrame<'a> { +impl AttachedPictureFrame<'_> { /// Create a new [`AttachedPictureFrame`] pub fn new(encoding: TextEncoding, picture: Picture) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/audio_text_frame.rs b/lofty/src/id3/v2/items/audio_text_frame.rs index b42e01213..8fc39259e 100644 --- a/lofty/src/id3/v2/items/audio_text_frame.rs +++ b/lofty/src/id3/v2/items/audio_text_frame.rs @@ -71,19 +71,19 @@ pub struct AudioTextFrame<'a> { pub audio_data: Vec, } -impl<'a> PartialEq for AudioTextFrame<'a> { +impl PartialEq for AudioTextFrame<'_> { fn eq(&self, other: &Self) -> bool { self.equivalent_text == other.equivalent_text } } -impl<'a> Hash for AudioTextFrame<'a> { +impl Hash for AudioTextFrame<'_> { fn hash(&self, state: &mut H) { self.equivalent_text.hash(state); } } -impl<'a> AudioTextFrame<'a> { +impl AudioTextFrame<'_> { /// Create a new [`AudioTextFrame`] pub fn new( encoding: TextEncoding, diff --git a/lofty/src/id3/v2/items/encapsulated_object.rs b/lofty/src/id3/v2/items/encapsulated_object.rs index 1c1882047..6bb694b3b 100644 --- a/lofty/src/id3/v2/items/encapsulated_object.rs +++ b/lofty/src/id3/v2/items/encapsulated_object.rs @@ -22,7 +22,7 @@ pub struct GeneralEncapsulatedObject<'a> { pub data: Vec, } -impl<'a> GeneralEncapsulatedObject<'a> { +impl GeneralEncapsulatedObject<'_> { /// Create a new [`GeneralEncapsulatedObject`] pub fn new( encoding: TextEncoding, diff --git a/lofty/src/id3/v2/items/event_timing_codes_frame.rs b/lofty/src/id3/v2/items/event_timing_codes_frame.rs index 4fcdeb69c..ba8dabc59 100644 --- a/lofty/src/id3/v2/items/event_timing_codes_frame.rs +++ b/lofty/src/id3/v2/items/event_timing_codes_frame.rs @@ -185,7 +185,7 @@ pub struct EventTimingCodesFrame<'a> { pub events: Vec, } -impl<'a> EventTimingCodesFrame<'a> { +impl EventTimingCodesFrame<'_> { /// Create a new [`EventTimingCodesFrame`] pub fn new(timestamp_format: TimestampFormat, events: Vec) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/extended_text_frame.rs b/lofty/src/id3/v2/items/extended_text_frame.rs index ca7ab896a..8758f9cbb 100644 --- a/lofty/src/id3/v2/items/extended_text_frame.rs +++ b/lofty/src/id3/v2/items/extended_text_frame.rs @@ -32,19 +32,19 @@ pub struct ExtendedTextFrame<'a> { pub content: String, } -impl<'a> PartialEq for ExtendedTextFrame<'a> { +impl PartialEq for ExtendedTextFrame<'_> { fn eq(&self, other: &Self) -> bool { self.description == other.description } } -impl<'a> Hash for ExtendedTextFrame<'a> { +impl Hash for ExtendedTextFrame<'_> { fn hash(&self, state: &mut H) { self.description.hash(state); } } -impl<'a> ExtendedTextFrame<'a> { +impl ExtendedTextFrame<'_> { /// Create a new [`ExtendedTextFrame`] pub fn new(encoding: TextEncoding, description: String, content: String) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/extended_url_frame.rs b/lofty/src/id3/v2/items/extended_url_frame.rs index 2bad5553f..c771caa1c 100644 --- a/lofty/src/id3/v2/items/extended_url_frame.rs +++ b/lofty/src/id3/v2/items/extended_url_frame.rs @@ -29,19 +29,19 @@ pub struct ExtendedUrlFrame<'a> { pub content: String, } -impl<'a> PartialEq for ExtendedUrlFrame<'a> { +impl PartialEq for ExtendedUrlFrame<'_> { fn eq(&self, other: &Self) -> bool { self.description == other.description } } -impl<'a> Hash for ExtendedUrlFrame<'a> { +impl Hash for ExtendedUrlFrame<'_> { fn hash(&self, state: &mut H) { self.description.hash(state); } } -impl<'a> ExtendedUrlFrame<'a> { +impl ExtendedUrlFrame<'_> { /// Create a new [`ExtendedUrlFrame`] pub fn new(encoding: TextEncoding, description: String, content: String) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/language_frame.rs b/lofty/src/id3/v2/items/language_frame.rs index 884a8adbd..71b9fe915 100644 --- a/lofty/src/id3/v2/items/language_frame.rs +++ b/lofty/src/id3/v2/items/language_frame.rs @@ -91,20 +91,20 @@ pub struct CommentFrame<'a> { pub content: String, } -impl<'a> PartialEq for CommentFrame<'a> { +impl PartialEq for CommentFrame<'_> { fn eq(&self, other: &Self) -> bool { self.language == other.language && self.description == other.description } } -impl<'a> Hash for CommentFrame<'a> { +impl Hash for CommentFrame<'_> { fn hash(&self, state: &mut H) { self.language.hash(state); self.description.hash(state); } } -impl<'a> CommentFrame<'a> { +impl CommentFrame<'_> { const FRAME_ID: FrameId<'static> = FrameId::Valid(Cow::Borrowed("COMM")); /// Create a new [`CommentFrame`] @@ -207,20 +207,20 @@ pub struct UnsynchronizedTextFrame<'a> { pub content: String, } -impl<'a> PartialEq for UnsynchronizedTextFrame<'a> { +impl PartialEq for UnsynchronizedTextFrame<'_> { fn eq(&self, other: &Self) -> bool { self.language == other.language && self.description == other.description } } -impl<'a> Hash for UnsynchronizedTextFrame<'a> { +impl Hash for UnsynchronizedTextFrame<'_> { fn hash(&self, state: &mut H) { self.language.hash(state); self.description.hash(state); } } -impl<'a> UnsynchronizedTextFrame<'a> { +impl UnsynchronizedTextFrame<'_> { const FRAME_ID: FrameId<'static> = FrameId::Valid(Cow::Borrowed("USLT")); /// Create a new [`UnsynchronizedTextFrame`] diff --git a/lofty/src/id3/v2/items/ownership_frame.rs b/lofty/src/id3/v2/items/ownership_frame.rs index 9da53f276..6ee53306b 100644 --- a/lofty/src/id3/v2/items/ownership_frame.rs +++ b/lofty/src/id3/v2/items/ownership_frame.rs @@ -33,7 +33,7 @@ pub struct OwnershipFrame<'a> { pub seller: String, } -impl<'a> OwnershipFrame<'a> { +impl OwnershipFrame<'_> { /// Create a new [`OwnershipFrame`] pub fn new( encoding: TextEncoding, diff --git a/lofty/src/id3/v2/items/popularimeter.rs b/lofty/src/id3/v2/items/popularimeter.rs index 4b36375c9..5d1d0dfd9 100644 --- a/lofty/src/id3/v2/items/popularimeter.rs +++ b/lofty/src/id3/v2/items/popularimeter.rs @@ -31,19 +31,19 @@ pub struct PopularimeterFrame<'a> { pub counter: u64, } -impl<'a> PartialEq for PopularimeterFrame<'a> { +impl PartialEq for PopularimeterFrame<'_> { fn eq(&self, other: &Self) -> bool { self.email == other.email } } -impl<'a> Hash for PopularimeterFrame<'a> { +impl Hash for PopularimeterFrame<'_> { fn hash(&self, state: &mut H) { self.email.hash(state); } } -impl<'a> PopularimeterFrame<'a> { +impl PopularimeterFrame<'_> { /// Create a new [`PopularimeterFrame`] pub fn new(email: String, rating: u8, counter: u64) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/private_frame.rs b/lofty/src/id3/v2/items/private_frame.rs index 9ded39628..3c04c8f1e 100644 --- a/lofty/src/id3/v2/items/private_frame.rs +++ b/lofty/src/id3/v2/items/private_frame.rs @@ -22,7 +22,7 @@ pub struct PrivateFrame<'a> { pub private_data: Vec, } -impl<'a> PrivateFrame<'a> { +impl PrivateFrame<'_> { /// Create a new [`PrivateFrame`] pub fn new(owner: String, private_data: Vec) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/relative_volume_adjustment_frame.rs b/lofty/src/id3/v2/items/relative_volume_adjustment_frame.rs index f3a09aff9..f2d0295ab 100644 --- a/lofty/src/id3/v2/items/relative_volume_adjustment_frame.rs +++ b/lofty/src/id3/v2/items/relative_volume_adjustment_frame.rs @@ -90,19 +90,19 @@ pub struct RelativeVolumeAdjustmentFrame<'a> { pub channels: HashMap, } -impl<'a> PartialEq for RelativeVolumeAdjustmentFrame<'a> { +impl PartialEq for RelativeVolumeAdjustmentFrame<'_> { fn eq(&self, other: &Self) -> bool { self.identification == other.identification } } -impl<'a> Hash for RelativeVolumeAdjustmentFrame<'a> { +impl Hash for RelativeVolumeAdjustmentFrame<'_> { fn hash(&self, state: &mut H) { self.identification.hash(state) } } -impl<'a> RelativeVolumeAdjustmentFrame<'a> { +impl RelativeVolumeAdjustmentFrame<'_> { /// Create a new [`RelativeVolumeAdjustmentFrame`] pub fn new(identification: String, channels: HashMap) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/id3/v2/items/sync_text.rs b/lofty/src/id3/v2/items/sync_text.rs index 69bc9549d..cd64aa78d 100644 --- a/lofty/src/id3/v2/items/sync_text.rs +++ b/lofty/src/id3/v2/items/sync_text.rs @@ -86,7 +86,7 @@ pub struct SynchronizedTextFrame<'a> { pub content: Vec<(u32, String)>, } -impl<'a> SynchronizedTextFrame<'a> { +impl SynchronizedTextFrame<'_> { /// Create a new [`SynchronizedTextFrame`] pub fn new( encoding: TextEncoding, diff --git a/lofty/src/id3/v2/items/timestamp_frame.rs b/lofty/src/id3/v2/items/timestamp_frame.rs index 4ff15302d..b1720149a 100644 --- a/lofty/src/id3/v2/items/timestamp_frame.rs +++ b/lofty/src/id3/v2/items/timestamp_frame.rs @@ -18,13 +18,13 @@ pub struct TimestampFrame<'a> { pub timestamp: Timestamp, } -impl<'a> PartialOrd for TimestampFrame<'a> { +impl PartialOrd for TimestampFrame<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl<'a> Ord for TimestampFrame<'a> { +impl Ord for TimestampFrame<'_> { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.timestamp.cmp(&other.timestamp) } diff --git a/lofty/src/id3/v2/items/unique_file_identifier.rs b/lofty/src/id3/v2/items/unique_file_identifier.rs index a718c024f..7d3893ab6 100644 --- a/lofty/src/id3/v2/items/unique_file_identifier.rs +++ b/lofty/src/id3/v2/items/unique_file_identifier.rs @@ -20,19 +20,19 @@ pub struct UniqueFileIdentifierFrame<'a> { pub identifier: Vec, } -impl<'a> PartialEq for UniqueFileIdentifierFrame<'a> { +impl PartialEq for UniqueFileIdentifierFrame<'_> { fn eq(&self, other: &Self) -> bool { self.owner == other.owner } } -impl<'a> Hash for UniqueFileIdentifierFrame<'a> { +impl Hash for UniqueFileIdentifierFrame<'_> { fn hash(&self, state: &mut H) { self.owner.hash(state); } } -impl<'a> UniqueFileIdentifierFrame<'a> { +impl UniqueFileIdentifierFrame<'_> { /// Create a new [`UniqueFileIdentifierFrame`] pub fn new(owner: String, identifier: Vec) -> Self { let header = FrameHeader::new(FRAME_ID, FrameFlags::default()); diff --git a/lofty/src/iff/aiff/tag.rs b/lofty/src/iff/aiff/tag.rs index 95e65f534..1af962b01 100644 --- a/lofty/src/iff/aiff/tag.rs +++ b/lofty/src/iff/aiff/tag.rs @@ -312,7 +312,7 @@ where pub comments: Option<&'a [Comment]>, } -impl<'a, T, AI> AiffTextChunksRef<'a, T, AI> +impl AiffTextChunksRef<'_, T, AI> where T: AsRef, AI: IntoIterator, diff --git a/lofty/src/mp4/ilst/ref.rs b/lofty/src/mp4/ilst/ref.rs index 1fa6c0141..929099b94 100644 --- a/lofty/src/mp4/ilst/ref.rs +++ b/lofty/src/mp4/ilst/ref.rs @@ -46,7 +46,7 @@ where } } -impl<'a> Atom<'a> { +impl Atom<'_> { pub(super) fn as_ref(&self) -> AtomRef<'_, impl IntoIterator> { AtomRef { ident: self.ident.as_borrowed(), diff --git a/lofty/src/mp4/write.rs b/lofty/src/mp4/write.rs index 41d28d752..83251257a 100644 --- a/lofty/src/mp4/write.rs +++ b/lofty/src/mp4/write.rs @@ -242,19 +242,19 @@ impl AtomWriterCompanion<'_> { } } -impl<'a> Seek for AtomWriterCompanion<'a> { +impl Seek for AtomWriterCompanion<'_> { fn seek(&mut self, pos: SeekFrom) -> std::io::Result { self.contents.seek(pos) } } -impl<'a> Read for AtomWriterCompanion<'a> { +impl Read for AtomWriterCompanion<'_> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.contents.read(buf) } } -impl<'a> Write for AtomWriterCompanion<'a> { +impl Write for AtomWriterCompanion<'_> { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.contents.write(buf) } diff --git a/lofty/src/wavpack/properties.rs b/lofty/src/wavpack/properties.rs index 9105415c7..72aa55384 100644 --- a/lofty/src/wavpack/properties.rs +++ b/lofty/src/wavpack/properties.rs @@ -187,7 +187,7 @@ where } total_samples = block_header.total_samples; - properties.bit_depth = ((((flags & BYTES_PER_SAMPLE_MASK) + 1) * 8) - ((flags & BIT_DEPTH_SHIFT_MASK) >> BIT_DEPTH_SHL)) as u8; + properties.bit_depth = (((flags & BYTES_PER_SAMPLE_MASK) + 1) * 8).saturating_sub((flags & BIT_DEPTH_SHIFT_MASK) >> BIT_DEPTH_SHL) as u8; properties.version = block_header.version; properties.lossless = flags & FLAG_HYBRID_COMPRESSION == 0; @@ -414,6 +414,10 @@ fn get_extended_meta_info( } // Skip over any remaining block size + if (size as usize) > reader.len() { + err!(SizeMismatch); + } + let (_, rem) = reader.split_at(size as usize); *reader = rem; diff --git a/lofty/tests/fuzz/assets/wavpackfile_read_from/crash-68a2215c732ecb202998d3bd8b0de932e5e0301d_minimized b/lofty/tests/fuzz/assets/wavpackfile_read_from/crash-68a2215c732ecb202998d3bd8b0de932e5e0301d_minimized new file mode 100644 index 000000000..2b3b94733 Binary files /dev/null and b/lofty/tests/fuzz/assets/wavpackfile_read_from/crash-68a2215c732ecb202998d3bd8b0de932e5e0301d_minimized differ diff --git a/lofty/tests/fuzz/assets/wavpackfile_read_from/crash-b583ce7029fc17100e2aabfa4679865a2a5fd9a4_minimized b/lofty/tests/fuzz/assets/wavpackfile_read_from/crash-b583ce7029fc17100e2aabfa4679865a2a5fd9a4_minimized new file mode 100644 index 000000000..5e5621ea5 Binary files /dev/null and b/lofty/tests/fuzz/assets/wavpackfile_read_from/crash-b583ce7029fc17100e2aabfa4679865a2a5fd9a4_minimized differ diff --git a/lofty/tests/fuzz/wavpackfile_read_from.rs b/lofty/tests/fuzz/wavpackfile_read_from.rs index fda138600..4f5e4ecc9 100644 --- a/lofty/tests/fuzz/wavpackfile_read_from.rs +++ b/lofty/tests/fuzz/wavpackfile_read_from.rs @@ -120,3 +120,19 @@ fn panic5() { ); let _ = WavPackFile::read_from(&mut reader, ParseOptions::default()); } + +#[test_log::test] +fn panic6() { + let mut reader = crate::get_reader( + "wavpackfile_read_from/crash-68a2215c732ecb202998d3bd8b0de932e5e0301d_minimized", + ); + let _ = WavPackFile::read_from(&mut reader, ParseOptions::default()); +} + +#[test_log::test] +fn panic7() { + let mut reader = crate::get_reader( + "wavpackfile_read_from/crash-b583ce7029fc17100e2aabfa4679865a2a5fd9a4_minimized", + ); + let _ = WavPackFile::read_from(&mut reader, ParseOptions::default()); +}