From 1f59f63b581de6a74e8040fae4f0da6ee63c4851 Mon Sep 17 00:00:00 2001 From: Nicholas Clark Date: Thu, 30 Oct 2025 11:12:45 -0700 Subject: [PATCH] disk images: fix some corner-cases in MBR calculation Fix some corner-cases with CHS calculation when filling out MBR partition tables. Make sure that CHS values are correctly clamped the requested LBA is too big to be representable as a CHS, and fix the calculation when LBA=0. When creating a hybrid GPT/MBR, change the GPT protective partition size from (hd->gpt_location / 512 + GPT_SECTORS - 2) to GPT_SECTORS, which is more generally correct (and evaluates to the same value in the hybrid case). Signed-off-by: Nicholas Clark --- image-hd.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/image-hd.c b/image-hd.c index 274c6ac..1b649db 100644 --- a/image-hd.c +++ b/image-hd.c @@ -116,15 +116,24 @@ static unsigned long long partition_end(const struct partition *part) static void lba_to_chs(unsigned int lba, unsigned char *chs) { - const unsigned int hpc = 255; - const unsigned int spt = 63; - unsigned int s, c; - - chs[0] = (lba / spt) % hpc; - c = (lba / (spt * hpc)); - s = (lba > 0) ? (lba % spt + 1) : 0; - chs[1] = ((c & 0x300) >> 2) | (s & 0xff); - chs[2] = (c & 0xff); + const unsigned int heads_per_cyl = 255; + const unsigned int sect_per_track = 63; + + if (lba > (1024 * heads_per_cyl * sect_per_track - 1)) { + chs[0] = 0xFE; + chs[1] = 0xFF; + chs[2] = 0xFF; + return; + } + + unsigned int cylinder = lba / (heads_per_cyl * sect_per_track); + unsigned int remainder = lba % (heads_per_cyl * sect_per_track); + unsigned int head = remainder / sect_per_track; + unsigned int sector = (remainder % sect_per_track) + 1; + + chs[0] = head & 0xFF; + chs[1] = (sector & 0x3F) + ((cylinder & 0x300) >> 2); + chs[2] = cylinder & 0xFF; } static void hdimage_setup_chs(struct mbr_partition_entry *entry, @@ -185,7 +194,7 @@ static int hdimage_insert_mbr(struct image *image, struct list_head *partitions) entry->partition_type = 0xee; entry->relative_sectors = 1; - entry->total_sectors = hd->gpt_location / 512 + GPT_SECTORS - 2; + entry->total_sectors = GPT_SECTORS; hdimage_setup_chs(entry, 0); }