From b2613f96f60e31fc384b1a357e61a9e6d8d98480 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Thu, 11 Jun 2026 23:15:31 +0200 Subject: [PATCH] ICO: Add header validation in strict mode --- src/codecs/ico/decoder.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/codecs/ico/decoder.rs b/src/codecs/ico/decoder.rs index 4504f5708b..d4ee700837 100644 --- a/src/codecs/ico/decoder.rs +++ b/src/codecs/ico/decoder.rs @@ -1,4 +1,4 @@ -use byteorder_lite::ReadBytesExt; +use byteorder_lite::{LittleEndian, ReadBytesExt}; use std::io::{BufRead, Read, Seek}; use std::{error, fmt}; @@ -159,7 +159,7 @@ impl IcoDecoder { spec: SpecCompliance, ) -> ImageResult> { let reader_offset = r.stream_position()?; - let entries = read_entries(&mut r)?; + let entries = read_entries(&mut r, spec)?; let entry = best_entry(entries)?; let decoder = entry.decoder(r, reader_offset)?; @@ -172,11 +172,28 @@ impl IcoDecoder { } } -fn read_entries(r: &mut R) -> ImageResult> { +fn read_entries(r: &mut R, spec: SpecCompliance) -> ImageResult> { let mut header = [0u8; 6]; r.read_exact(&mut header)?; - // header[0..2] = reserved, header[2..4] = type, header[4..6] = count - let count = u16::from_le_bytes(header[4..6].try_into().unwrap()); + let mut header = header.as_slice(); + + let reserved = header.read_u16::()?; + let id_type = header.read_u16::()?; + let count = header.read_u16::()?; + + if spec == SpecCompliance::Strict && reserved != 0 { + return Err(ImageError::Decoding(DecodingError::new( + ImageFormat::Ico.into(), + format!("Reserved field must be 0, but found 0x{reserved:X}"), + ))); + } + if spec == SpecCompliance::Strict && !matches!(id_type, 1 | 2) { + return Err(ImageError::Decoding(DecodingError::new( + ImageFormat::Ico.into(), + format!("Invalid header type. Expected 1 (ICO) or 2 (CUR), but found {id_type}"), + ))); + } + (0..count).map(|_| read_entry(r)).collect() }