block: qcow: Test rejection when backing file offset equals cluster size

A backing file string placed exactly at cluster_size starts past
the first cluster boundary, so QcowHeader::new must reject it.

Introduce a read_header_with_patched_backing helper that builds
a valid header, patches backing_file_offset and backing_file_size,
writes it out and re-parses it. Use it to cover this case.

Assisted-by: Claude:Opus-4.7
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-05-29 19:30:40 +02:00
committed by Rob Bradford
parent 53a9ae08c2
commit 2d8811ad82

View File

@@ -2434,6 +2434,7 @@ mod unit_tests {
use vmm_sys_util::tempfile::TempFile;
use vmm_sys_util::write_zeroes::WriteZeroes;
use super::header::DEFAULT_CLUSTER_BITS;
use super::util::{COMPRESSED_FLAG, ZERO_FLAG};
use super::*;
use crate::formats::qcow::common::unit_tests::compress_allocated_clusters;
@@ -2695,6 +2696,37 @@ mod unit_tests {
);
}
/// Write a header to a fresh file with backing_file_offset and
/// backing_file_size patched. Panics on setup failures, returns
/// the parse result of the patched header.
fn read_header_with_patched_backing(offset: u64, size: u32) -> Result<QcowHeader> {
let mut header = QcowHeader::create_for_size_and_path(3, 0x10_0000, None)
.expect("Failed to create header.");
header.backing_file_offset = offset;
header.backing_file_size = size;
let mut disk_file: RawFile = RawFile::new(
TempFile::new()
.expect("Failed to create temp file.")
.into_file(),
false,
);
header
.write_to(&mut disk_file)
.expect("Failed to write header.");
disk_file.rewind().expect("Failed to rewind disk file.");
QcowHeader::new(&mut disk_file)
}
#[test]
fn backing_file_offset_at_cluster_boundary() {
let cluster_size = 1u64 << DEFAULT_CLUSTER_BITS;
let err = read_header_with_patched_backing(cluster_size, 1).unwrap_err();
assert!(matches!(
err,
Error::BackingFileOutsideFirstCluster(_, _, _)
));
}
/// Helper to create a test file with header extensions
fn create_header_with_extension(ext_type: u32, ext_data: &[u8]) -> (RawFile, QcowHeader) {
let header = QcowHeader::create_for_size_and_path(3, 0x10_0000, None)