From 0667e564f014bcf132ba26067bd840eca82f4d7c Mon Sep 17 00:00:00 2001 From: cenhuilin Date: Mon, 14 Jul 2025 16:25:43 +0800 Subject: [PATCH] fix default partition offset creates overlapping partitions --- ...disk-dos-fix-default-partition-start.patch | 169 ++++++++++++++++++ ...t-free-sector-detection-if-partition.patch | 41 +++++ ...l-correctly-gaps-if-default-start-re.patch | 122 +++++++++++++ util-linux.spec | 11 +- 4 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 backport-libfdisk-dos-fix-default-partition-start.patch create mode 100644 backport-libfdisk-fix-last-free-sector-detection-if-partition.patch create mode 100644 backport-tests-sfdisk-fill-correctly-gaps-if-default-start-re.patch diff --git a/backport-libfdisk-dos-fix-default-partition-start.patch b/backport-libfdisk-dos-fix-default-partition-start.patch new file mode 100644 index 0000000..cf26946 --- /dev/null +++ b/backport-libfdisk-dos-fix-default-partition-start.patch @@ -0,0 +1,169 @@ +From 83fdb880b953164fec7cc603c4ece11cb78762db Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 14 Jul 2025 15:57:02 +0800 +Subject: [PATCH] libfdisk: (dos) fix default partition start + +The current code implements the default start as first free space, but +it does not check if the space is large enough. + +Addresses: https://github.com/karelzak/util-linux/issues/1044 +Signed-off-by: Karel Zak +--- + libfdisk/src/alignment.c | 4 +- + libfdisk/src/dos.c | 81 +++++++++++++++++++++++++++++++++++++--- + 2 files changed, 78 insertions(+), 7 deletions(-) + +diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c +index 4ae5ff0..50a1528 100644 +--- a/libfdisk/src/alignment.c ++++ b/libfdisk/src/alignment.c +@@ -110,7 +110,7 @@ fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, in + res += sects_in_phy; + } + } +- ++/* + if (lba != res) + DBG(CXT, ul_debugobj(cxt, "LBA %12ju aligned-%s %12ju [grain=%lus]", + (uintmax_t) lba, +@@ -120,7 +120,7 @@ fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, in + cxt->grain / cxt->sector_size)); + else + DBG(CXT, ul_debugobj(cxt, "LBA %12ju already aligned", (uintmax_t)lba)); +- ++*/ + return res; + } + +diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c +index 439f5aa..7c75d0e 100644 +--- a/libfdisk/src/dos.c ++++ b/libfdisk/src/dos.c +@@ -980,6 +980,52 @@ static int get_start_from_user( struct fdisk_context *cxt, + return 0; + } + ++/* Returns last available sector in the free space pointed to by start. */ ++static int find_last_free( ++ struct fdisk_context *cxt, ++ int logical, ++ fdisk_sector_t begin, ++ fdisk_sector_t stop, ++ fdisk_sector_t *result) ++{ ++ fdisk_sector_t last = stop; ++ ++ size_t i = logical ? 4 : 0; ++ ++ for ( ; i < cxt->label->nparts_max; i++) { ++ struct pte *pe = self_pte(cxt, i); ++ ++ assert(pe); ++ fdisk_sector_t p_start = get_abs_partition_start(pe); ++ fdisk_sector_t p_end = get_abs_partition_end(pe); ++ ++ if (is_cleared_partition(pe->pt_entry)) ++ continue; ++ /* count EBR and begin of the logical partition as used area */ ++ if (pe->offset) ++ p_start -= cxt->first_lba; ++ ++ if ((p_start >= begin && p_start <= last) || ++ (p_end >= begin && p_end <= last)) { ++ last = p_start - 1; ++ } ++ if (last < begin) { ++ DBG(LABEL, ul_debug("no free space <%ju,%ju>", ++ (uintmax_t) begin, (uintmax_t) stop)); ++ return -ENOSPC; ++ } ++ } ++ ++ if (last == begin) ++ last = stop; ++ ++ DBG(LABEL, ul_debug("DOS: last free sector <%ju,%ju>: %ju", ++ (uintmax_t) begin, (uintmax_t) stop, (uintmax_t) last)); ++ ++ *result = last; ++ return 0; ++} ++ + static int find_last_free_sector_in_range( + struct fdisk_context *cxt, + int logical, +@@ -1105,6 +1151,7 @@ static int get_disk_ranges(struct fdisk_context *cxt, int logical, + return 0; + } + ++/* first free sector on disk */ + static int find_first_free_sector(struct fdisk_context *cxt, + int logical, + fdisk_sector_t start, +@@ -1174,6 +1221,7 @@ static int add_partition(struct fdisk_context *cxt, size_t n, + + temp = start; + ++ DBG(LABEL, ul_debug("DOS: >>> search for first free from %ju", start)); + rc = find_first_free_sector(cxt, is_logical, start, &dflt); + if (rc == -ENOSPC) + fdisk_warnx(cxt, _("No free sectors available.")); +@@ -1200,12 +1248,11 @@ static int add_partition(struct fdisk_context *cxt, size_t n, + break; + if (start >= temp + fdisk_get_units_per_sector(cxt) + && read) { +- fdisk_info(cxt, _("Sector %llu is already allocated."), +- temp); ++ if (!pa || !pa->start_follow_default) ++ fdisk_info(cxt, _("Sector %llu is already allocated."), temp); + temp = start; + read = 0; +- if (pa && (fdisk_partition_has_start(pa) || +- pa->start_follow_default)) ++ if (pa && fdisk_partition_has_start(pa)) + break; + } + +@@ -1215,6 +1262,30 @@ static int add_partition(struct fdisk_context *cxt, size_t n, + return rc; + read = 1; + } ++ if (pa && fdisk_partition_has_size(pa)) { ++ fdisk_sector_t last; ++ ++ rc = find_last_free(cxt, is_logical, start, limit, &last); ++ ++ if (rc == 0 && last - start + 1 < fdisk_partition_get_size(pa)) { ++ DBG(LABEL, ul_debug("DOS: area <%ju,%ju> too small [wanted=%ju aval=%ju]", ++ (uintmax_t) start, (uintmax_t) last, ++ fdisk_partition_get_size(pa), ++ last - start)); ++ ++ if (fdisk_partition_has_start(pa)) ++ rc = -ENOSPC; ++ else { ++ start = last + 1; ++ continue; ++ } ++ } ++ if (rc == -ENOSPC) { ++ fdisk_warnx(cxt, _("No free sectors available.")); ++ return rc; ++ } ++ } ++ + } while (start != temp || !read); + + if (n == 4) { +@@ -1236,7 +1307,7 @@ static int add_partition(struct fdisk_context *cxt, size_t n, + } + } + +- rc = find_last_free_sector_in_range(cxt, is_logical, start, limit, &stop); ++ rc = find_last_free(cxt, is_logical, start, limit, &stop); + if (rc == -ENOSPC) + fdisk_warnx(cxt, _("No free sectors available.")); + if (rc) +-- +2.43.0 + diff --git a/backport-libfdisk-fix-last-free-sector-detection-if-partition.patch b/backport-libfdisk-fix-last-free-sector-detection-if-partition.patch new file mode 100644 index 0000000..1e57d01 --- /dev/null +++ b/backport-libfdisk-fix-last-free-sector-detection-if-partition.patch @@ -0,0 +1,41 @@ +From 4fe7f9b614e2b5bb97f6d89af02acb867cffccc1 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 14 Jul 2025 16:10:23 +0800 +Subject: [PATCH] libfdisk: fix last free sector detection if partition size specified + +We need to skip useless gaps between partition if the gap is no large +enough for a new partition. Unfortunately, the current code checks +size of the gap, but does not care for location of the gap -- this is +good enough for dialog driven partitioning, but it's pretty bad if +start of the partition is explicitly specified (e.g. sfdisk). + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1860461 +Signed-off-by: Karel Zak +--- + libfdisk/src/dos.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c +index 7c75d0e..9ee0fce 100644 +--- a/libfdisk/src/dos.c ++++ b/libfdisk/src/dos.c +@@ -1266,14 +1266,14 @@ static int add_partition(struct fdisk_context *cxt, size_t n, + fdisk_sector_t last; + + rc = find_last_free(cxt, is_logical, start, limit, &last); +- + if (rc == 0 && last - start + 1 < fdisk_partition_get_size(pa)) { + DBG(LABEL, ul_debug("DOS: area <%ju,%ju> too small [wanted=%ju aval=%ju]", + (uintmax_t) start, (uintmax_t) last, + fdisk_partition_get_size(pa), + last - start)); + +- if (fdisk_partition_has_start(pa)) ++ if (fdisk_partition_has_start(pa) ++ && fdisk_partition_get_start(pa) <= last) + rc = -ENOSPC; + else { + start = last + 1; +-- +2.43.0 + diff --git a/backport-tests-sfdisk-fill-correctly-gaps-if-default-start-re.patch b/backport-tests-sfdisk-fill-correctly-gaps-if-default-start-re.patch new file mode 100644 index 0000000..0b5878d --- /dev/null +++ b/backport-tests-sfdisk-fill-correctly-gaps-if-default-start-re.patch @@ -0,0 +1,122 @@ +From fd3a8fda9a20cd83dbd7481a2864f0947f39eb3e Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 14 Jul 2025 16:04:15 +0800 +Subject: [PATCH] tests: sfdisk fill correctly gaps if default start requested + +References: 83fdb880b953164fec7cc603c4ece11cb78762db +Addresses: https://github.com/karelzak/util-linux/issues/1044 +Signed-off-by: Karel Zak +--- + tests/expected/sfdisk/dos-default-vs-gap1 | 24 ++++++++++++++++++ + tests/expected/sfdisk/dos-default-vs-gap2 | 30 +++++++++++++++++++++++ + tests/ts/sfdisk/dos | 28 +++++++++++++++++++++ + 3 files changed, 82 insertions(+) + create mode 100644 tests/expected/sfdisk/dos-default-vs-gap1 + create mode 100644 tests/expected/sfdisk/dos-default-vs-gap2 + +diff --git a/tests/expected/sfdisk/dos-default-vs-gap1 b/tests/expected/sfdisk/dos-default-vs-gap1 +new file mode 100644 +index 0000000..9539d22 +--- /dev/null ++++ b/tests/expected/sfdisk/dos-default-vs-gap1 +@@ -0,0 +1,24 @@ ++Checking that no-one is using this disk right now ... OK ++ ++Disk : 50 MiB, 52428800 bytes, 102400 sectors ++Disk model: scsi_debug ++Units: sectors of 1 * 512 = 512 bytes ++Sector size (logical/physical): 512 bytes / 4096 bytes ++I/O size (minimum/optimal): 4096 bytes / bytes ++ ++>>> Created a new disklabel. ++1: Created a new partition . ++2: Created a new partition . ++3: Done. ++ ++New situation: ++Disklabel type: dos ++Disk identifier: ++ ++Device Boot Start End Sectors Size Id Type ++1 6144 16383 10240 5M 83 Linux ++2 16384 28671 12288 6M 83 Linux ++ ++The partition table has been altered. ++Calling ioctl() to re-read partition table. ++Syncing disks. +diff --git a/tests/expected/sfdisk/dos-default-vs-gap2 b/tests/expected/sfdisk/dos-default-vs-gap2 +new file mode 100644 +index 0000000..e76f704 +--- /dev/null ++++ b/tests/expected/sfdisk/dos-default-vs-gap2 +@@ -0,0 +1,30 @@ ++Checking that no-one is using this disk right now ... OK ++ ++Disk : 50 MiB, 52428800 bytes, 102400 sectors ++Disk model: scsi_debug ++Units: sectors of 1 * 512 = 512 bytes ++Sector size (logical/physical): 512 bytes / 4096 bytes ++I/O size (minimum/optimal): 4096 bytes / bytes ++ ++>>> Created a new disklabel. ++1: Created a new partition . ++2: Created a new partition . ++3: Created a new partition . ++4: Created a new partition . ++All partitions used. ++ ++New situation: ++Disklabel type: dos ++Disk identifier: ++ ++Device Boot Start End Sectors Size Id Type ++1 8192 14335 6144 3M 83 Linux ++2 26624 36863 10240 5M 83 Linux ++3 14336 22527 8192 4M 83 Linux ++4 2048 6143 4096 2M 83 Linux ++ ++Partition table entries are not in disk order. ++ ++The partition table has been altered. ++Calling ioctl() to re-read partition table. ++Syncing disks. +diff --git a/tests/ts/sfdisk/dos b/tests/ts/sfdisk/dos +index 6887c47..a2fd728 100755 +--- a/tests/ts/sfdisk/dos ++++ b/tests/ts/sfdisk/dos +@@ -232,4 +232,32 @@ ts_fdisk_clean $TS_DEVICE + udevadm settle + ts_finalize_subtest + ++ ++ts_init_subtest "default-vs-gap1" ++$TS_CMD_WIPEFS -a ${TS_DEVICE} &> /dev/null ++udevadm settle ++$TS_CMD_SFDISK ${TS_DEVICE} >> $TS_OUTPUT 2>> $TS_ERRLOG < /dev/null ++udevadm settle ++$TS_CMD_SFDISK ${TS_DEVICE} >> $TS_OUTPUT 2>> $TS_ERRLOG < - 2.35.2-21 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:fix default partition offset creates overlapping partitions + * Mon Apr 14 2025 hugel - 2.35.2-20 - Type:bugfix - CVE:NA -- Gitee