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 <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-06-01 16:11:22 +02:00
committed by Rob Bradford
parent 4a2a9390be
commit 4294a4b862
2 changed files with 9 additions and 0 deletions

View File

@@ -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
{

View File

@@ -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")]