From 2314c371a87e5a8707bedfd9be9ca5b9a4bf30ef Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Thu, 7 Aug 2025 01:36:22 -0400 Subject: [PATCH] sparse: Fix u32 overflow when unpacking files with large holes CHUNK_TYPE_RAW is the only chunk type that's guaranteed to not overflow a u32 when its number of blocks is multiplied by the block size. CHUNK_TYPE_FILL and CHUNK_TYPE_DONT_CARE require a u64. Issue: #472 Signed-off-by: Andrew Gunnerson --- avbroot/src/cli/sparse.rs | 8 ++++---- avbroot/src/format/sparse.rs | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/avbroot/src/cli/sparse.rs b/avbroot/src/cli/sparse.rs index 152d280..a657eb5 100644 --- a/avbroot/src/cli/sparse.rs +++ b/avbroot/src/cli/sparse.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 Andrew Gunnerson +// SPDX-FileCopyrightText: 2024-2025 Andrew Gunnerson // SPDX-License-Identifier: GPL-3.0-only use std::{ @@ -317,11 +317,11 @@ fn unpack_subcommand( })?; } ChunkData::Hole => { - // This cannot overflow. - let to_skip = chunk.bounds.len() * metadata.header.block_size; + // Unlike ChunkData::Data, this can overflow a u32. + let to_skip = i64::from(chunk.bounds.len()) * i64::from(metadata.header.block_size); writer - .seek(SeekFrom::Current(to_skip.into())) + .seek(SeekFrom::Current(to_skip)) .with_context(|| format!("Failed to seek file: {:?}", cli.output))?; } ChunkData::Crc32(_) => {} diff --git a/avbroot/src/format/sparse.rs b/avbroot/src/format/sparse.rs index a1c1ed1..8e4f918 100644 --- a/avbroot/src/format/sparse.rs +++ b/avbroot/src/format/sparse.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 Andrew Gunnerson +// SPDX-FileCopyrightText: 2024-2025 Andrew Gunnerson // SPDX-License-Identifier: GPL-3.0-only use std::{ @@ -374,6 +374,9 @@ impl fmt::Debug for ChunkData { /// metadata they contain. #[derive(Clone, Copy, PartialEq, Eq)] pub struct Chunk { + /// When [`Self::data`] is [`ChunkData::Data`], this is guaranteed to not + /// exceed the bounds of [`u32`] when multiplied by [`Header::block_size`]. + /// For other types of data, a 64-bit signed or unsigned integer is needed. pub bounds: ChunkBounds, pub data: ChunkData, }