From 4294a4b86294ba8204f998a3a0f4808d87d5493f Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 1 Jun 2026 16:11:22 +0200 Subject: [PATCH] block: qcow: Reject backing file name overlapping the header The qcow2 spec requires the backing file name string to live in the remaining space between the end of the header extension area and the end of the first cluster. Header parsing accepted any backing file offset above zero, including offsets pointing into the fixed header fields themselves, so a corrupt or malicious image could redirect the parser into reinterpreting header bytes as the backing path. Reject any backing_file_offset that is less than header.header_size via a new BackingFileOverlapsHeader error. The check fires before the existing first cluster bound, since an overlap is a different class of corruption and deserves a distinct diagnostic. Ref: #8261 Signed-off-by: Anatol Belski --- block/src/formats/qcow/internal/header.rs | 7 +++++++ block/src/formats/qcow/internal/mod.rs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/block/src/formats/qcow/internal/header.rs b/block/src/formats/qcow/internal/header.rs index 030815438..1989f25e3 100644 --- a/block/src/formats/qcow/internal/header.rs +++ b/block/src/formats/qcow/internal/header.rs @@ -335,6 +335,13 @@ impl QcowHeader { let cluster_size = 1u64 .checked_shl(header.cluster_bits) .ok_or(Error::InvalidClusterSize)?; + if header.backing_file_offset < u64::from(header.header_size) { + return Err(Error::BackingFileOverlapsHeader( + header.backing_file_offset, + header.backing_file_size, + header.header_size, + )); + } if header.backing_file_offset >= cluster_size || header.backing_file_offset + u64::from(header.backing_file_size) > cluster_size { diff --git a/block/src/formats/qcow/internal/mod.rs b/block/src/formats/qcow/internal/mod.rs index a2da14318..8e436d0ea 100644 --- a/block/src/formats/qcow/internal/mod.rs +++ b/block/src/formats/qcow/internal/mod.rs @@ -72,6 +72,8 @@ pub enum Error { "Backing file name at offset {0:#x} length {1:#x} lies outside first cluster of {2:#x}" )] BackingFileOutsideFirstCluster(u64, u32, u64), + #[error("Backing file name at offset {0:#x} length {1:#x} overlaps header of size {2:#x}")] + BackingFileOverlapsHeader(u64, u32, u32), #[error("Backing file support is disabled")] BackingFilesDisabled, #[error("Backing file name is too long: {0} bytes over")]