From bcl at redhat.com Tue Nov 4 18:55:55 2025 From: bcl at redhat.com (Brian C. Lane) Date: Tue, 4 Nov 2025 10:55:55 -0800 Subject: [parted-devel] [PATCH 2/2] tests: Add test for partition table not at LBA 2 In-Reply-To: <20251104185555.44599-1-bcl@redhat.com> References: <20251104185555.44599-1-bcl@redhat.com> Message-ID: <20251104185555.44599-2-bcl@redhat.com> Use sgdisk to create a disk image with the partition table relocated to sector 16, and shrunk to 40 entries. Then test that parted in script mode aborts making changes and outputs the error message. --- tests/Makefile.am | 1 + tests/t-lib-helpers.sh | 6 ++++++ tests/t0284-gpt-moved-pth.sh | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 tests/t0284-gpt-moved-pth.sh diff --git a/tests/Makefile.am b/tests/Makefile.am index 5eeab08..a37eb0e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -31,6 +31,7 @@ TESTS = \ t0281-gpt-grow.sh \ t0282-gpt-move-backup.sh \ t0283-overlap-partitions.sh \ + t0284-gpt-moved-pth.sh \ t0290-gpt-name.sh \ t0300-dos-on-gpt.sh \ t0301-overwrite-gpt-pmbr.sh \ diff --git a/tests/t-lib-helpers.sh b/tests/t-lib-helpers.sh index a1d3c30..06a1e4f 100644 --- a/tests/t-lib-helpers.sh +++ b/tests/t-lib-helpers.sh @@ -29,6 +29,12 @@ require_fat_() || skip_ "mkfs.vfat: command not found" } +require_sgdisk_() +{ + sgdisk -? 2>&1 | grep '^Usage:' \ + || skip_ "sgdisk: command not found" +} + # Skip this test if we're not in SELinux "enforcing" mode. require_selinux_enforcing_() { diff --git a/tests/t0284-gpt-moved-pth.sh b/tests/t0284-gpt-moved-pth.sh new file mode 100644 index 0000000..258a6ce --- /dev/null +++ b/tests/t0284-gpt-moved-pth.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# Test parted behavior when partition table is not at LBA 2 + +# Copyright (C) 2025 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. "${srcdir=.}/init.sh"; path_prepend_ ../parted + +require_512_byte_sector_size_ +require_sgdisk_ + +dev=loop-file +ss=$sector_size_ +n_sectors=5000 + +dd if=/dev/null of=$dev bs=$ss seek=$n_sectors || fail=1 + +# Use sgdisk to create a GPT disklabel with the partition table at sector 16 +# and limited to 40 entries. +sgdisk --move-main-table=16 --resize-table=40 "$dev" || fail=1 + +# Trying to create a partition should exit with a message and rc=1 +parted -s "$dev" mkpart root ext4 2048s 4900s > out 2>&1; test $? = 1 || fail=1 +grep "^Error: The Partition Entry Table is not at LBA 2" out || fail=1 + +exit $fail -- 2.51.1 From bcl at redhat.com Tue Nov 4 18:55:54 2025 From: bcl at redhat.com (Brian C. Lane) Date: Tue, 4 Nov 2025 10:55:54 -0800 Subject: [parted-devel] [PATCH 1/2] gpt: Check for a relocated partition table Message-ID: <20251104185555.44599-1-bcl@redhat.com> Other tools, such as gdisk, can relocate the PartitionTableLBA so that it doesn't interfere with some bootloaders. Parted does not support using other locations at this time, and will silently rewrite the partition header using LBA 2, possibly overwriting bootloader data. This change adds a test to gpt_read that will prompt the user for confirmation if PartitionTableLBA is not at LBA 2, allowing them to cancel the operation and protect their bootloader data. This does not support '--fix' mode because there may be cases where a user take a disk image, expects to grow it to fit their new disk with --fix but it also contains a relocated partition table. If this happens we want to leave the image alone and allow them to use other tools. --- gnulib | 2 +- libparted/labels/gpt.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/gnulib b/gnulib index 480a59b..f4038dc 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 480a59ba60fa0b43a1cebe218bbcea6a947f1e86 +Subproject commit f4038dcb346fccb58d910e2f0a62c0f45022d2a8 diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c index 780fb70..8c7cb61 100644 --- a/libparted/labels/gpt.c +++ b/libparted/labels/gpt.c @@ -1034,6 +1034,22 @@ gpt_read (PedDisk *disk) } } #endif /* !DISCOVER_ONLY */ + + // Does the current header point to LBA2? If not, it will be overwritten, possibly + // erasing data. Ask the user if this is ok. + if (PED_LE64_TO_CPU (primary_gpt->PartitionEntryLBA) != GPT_PRIMARY_PART_TABLE_LBA) { + if (ped_exception_throw + (PED_EXCEPTION_ERROR, + (PED_EXCEPTION_YES | PED_EXCEPTION_NO), + _("The Partition Entry Table is not at LBA 2, if you continue it will " + "be relocated to LBA 2, possibly overwriting bootloader data. " + "Continue and overwrite LBA 2?")) != PED_EXCEPTION_YES) + { + goto error; + } + write_back = 1; + } + pth_free (backup_gpt); gpt = primary_gpt; } @@ -1057,6 +1073,21 @@ gpt_read (PedDisk *disk) == PED_EXCEPTION_CANCEL) goto error_free_gpt; + // Does the current header point to LBA2? If not, it will be overwritten, possibly + // erasing data. Ask the user if this is ok. + if (PED_LE64_TO_CPU (primary_gpt->PartitionEntryLBA) != GPT_PRIMARY_PART_TABLE_LBA) { + if (ped_exception_throw + (PED_EXCEPTION_ERROR, + (PED_EXCEPTION_YES | PED_EXCEPTION_CANCEL), + _("The Partition Entry Table is not at LBA 2, if you continue it will " + "be relocated to LBA 2, possibly overwriting bootloader data. " + "Continue and overwrite LBA 2?")) != PED_EXCEPTION_YES) + { + goto error_free_gpt; + } + write_back = 1; + } + gpt = primary_gpt; } else /* !primary_gpt && backup_gpt */ -- 2.51.1 From pascal at plouf.fr.eu.org Tue Nov 4 21:07:28 2025 From: pascal at plouf.fr.eu.org (Pascal Hambourg) Date: Tue, 4 Nov 2025 22:07:28 +0100 Subject: [parted-devel] [PATCH] disk.c: Update metadata after reading partition table Message-ID: <5c465100-ddf3-480f-b060-1c943a41ccbe@plouf.fr.eu.org> Make sure metadata and free space are updated after reading the partition table. Else non-standard metadata length for an empty GPT table may be incorrectly reported until a change is performed. Fixes: #79720 Signed-off-by: Pascal Hambourg --- libparted/disk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libparted/disk.c b/libparted/disk.c index 0db7b5c9..35148100 100644 --- a/libparted/disk.c +++ b/libparted/disk.c @@ -200,6 +200,11 @@ ped_disk_new (PedDevice* dev) goto error_close_dev; if (!type->ops->read (disk)) goto error_destroy_disk; + /* Kludge to make sure metadata are updated after read */ + if (!_disk_push_update_mode (disk)) + goto error_destroy_disk; + if (!_disk_pop_update_mode (disk)) + goto error_destroy_disk; disk->needs_clobber = 0; ped_device_close (dev); return disk; -- 2.39.5 From pascal at plouf.fr.eu.org Wed Nov 19 18:42:57 2025 From: pascal at plouf.fr.eu.org (Pascal Hambourg) Date: Wed, 19 Nov 2025 18:42:57 -0000 Subject: [parted-devel] [PATCH 0/2] gpt: Preserve relocated primary partition table Message-ID: The primary GPT partition entry array may start at a LBA other than the default in order to not interfere with the boot loader for some ARM SoC E.g.: - The boot loader for Freescale/NXP i.MX < 8 family must start at LBA 2. - The boot loader for older Allwinner sunxi family must start at LBA 16. This patchset also splits the metadata at the beginning of the disk in two: - protective MBR + primary GPT header - primary GPT partition entry array This makes it possible to see the gap between them and check if the metadata layout may interfere with the boot loader. However it would be better if the gap was not reported as free space. Is there a way to avoid this ? Pascal Hambourg (2): gpt: Preserve primary partition entry array location gpt: Recalculate PrimaryPartitionEntryLBA when primary partition table is invalid libparted/labels/gpt.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) -- 2.39.5 From pascal at plouf.fr.eu.org Wed Nov 19 18:44:17 2025 From: pascal at plouf.fr.eu.org (Pascal Hambourg) Date: Wed, 19 Nov 2025 18:44:17 -0000 Subject: [parted-devel] [PATCH 1/2] gpt: Preserve primary partition entry array location References: Message-ID: The primary partition entry array may start at a location other than LBA 2 in order to not overlap with the boot loader for some ARM SoCs. E.g.: - The boot loader for Freescale/NXP i.MX < 8 family must start at LBA 2. - The boot loader for older Allwinner sunxi family must start at LBA 16. --- libparted/labels/gpt.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c index 780fb705..87261dbd 100644 --- a/libparted/labels/gpt.c +++ b/libparted/labels/gpt.c @@ -351,6 +351,7 @@ struct __attribute__ ((packed, aligned(8))) _GPTDiskData efi_guid_t uuid; int pmbr_boot; PedSector AlternateLBA; + PedSector PrimaryPartitionEntryLBA; }; /* uses libparted's disk_specific field in PedPartition, to store our info */ @@ -601,6 +602,7 @@ gpt_alloc (const PedDevice *dev) uuid_generate ((unsigned char *) &gpt_disk_data->uuid); swap_uuid_and_efi_guid (&gpt_disk_data->uuid); gpt_disk_data->pmbr_boot = 0; + gpt_disk_data->PrimaryPartitionEntryLBA = GPT_PRIMARY_PART_TABLE_LBA; return disk; error_free_disk: @@ -1036,6 +1038,8 @@ gpt_read (PedDisk *disk) #endif /* !DISCOVER_ONLY */ pth_free (backup_gpt); gpt = primary_gpt; + gpt_disk_data->PrimaryPartitionEntryLBA = + PED_LE64_TO_CPU (primary_gpt->PartitionEntryLBA); } else if (!primary_gpt && !backup_gpt) { @@ -1058,6 +1062,8 @@ gpt_read (PedDisk *disk) goto error_free_gpt; gpt = primary_gpt; + gpt_disk_data->PrimaryPartitionEntryLBA = + PED_LE64_TO_CPU (primary_gpt->PartitionEntryLBA); } else /* !primary_gpt && backup_gpt */ { @@ -1212,7 +1218,8 @@ _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc, { gpt->MyLBA = PED_CPU_TO_LE64 (1); gpt->AlternateLBA = PED_CPU_TO_LE64 (gpt_disk_data->AlternateLBA); - gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2); + gpt->PartitionEntryLBA = + PED_CPU_TO_LE64 (gpt_disk_data->PrimaryPartitionEntryLBA); } gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start); @@ -1301,7 +1308,8 @@ gpt_write (const PedDisk *disk) free (pth_raw); if (!write_ok) goto error_free_ptes; - if (!ped_device_write (disk->dev, ptes, 2, ptes_sectors)) + if (!ped_device_write (disk->dev, ptes, + gpt_disk_data->PrimaryPartitionEntryLBA, ptes_sectors)) goto error_free_ptes; /* Write Alternate PTH & PTEs */ @@ -1515,8 +1523,10 @@ gpt_alloc_metadata (PedDisk *disk) disk->dev->sector_size); /* metadata at the start of the disk includes the MBR */ - if (!add_metadata_part (disk, GPT_PMBR_LBA, - GPT_PMBR_SECTORS + gptlength + pteslength)) + if (!add_metadata_part (disk, GPT_PMBR_LBA, GPT_PMBR_SECTORS + gptlength)) + return 0; + if (!add_metadata_part (disk, gpt_disk_data->PrimaryPartitionEntryLBA, + pteslength)) return 0; /* metadata at the end of the disk */ -- 2.39.5 From pascal at plouf.fr.eu.org Wed Nov 19 18:44:48 2025 From: pascal at plouf.fr.eu.org (Pascal Hambourg) Date: Wed, 19 Nov 2025 18:44:48 -0000 Subject: [parted-devel] [PATCH 2/2] gpt: Recalculate PrimaryPartitionEntryLBA when primary partition table is invalid References: Message-ID: When the primary partition table is invalid, the primary PartitionEntryLBA may be reset at two possible locations: - just after the primary header - just before the FirstUsableLBA On some platforms based on ARM SoCs, a boot loader may be present at any location between the primary header and the FirstUsableLBA. E.g.: - Allwinner family: start 8KiB, end < 1MiB - NXP/Freescale i.MX family: start 1KiB, end < 1MiB - OLPC XO (Marvell Armada): start 31.5KiB, end < 64KiB - BeagleBoard-X15, BeagleBone Black (TI OMAP): start 128KiB, end ~2MiB - Rockchip family (RK3288, RK3328, RK3399): start 32KiB, end ~10MB A boot loader which starts before LBA 34 may interfere with the primary PEA, so the primary PEA may have been moved after the boot loader. A boot loader which ends after 1MiB may interfere with partitions using default alignment, so the FirstUsableLBA may have been moved after the boot loader. >From the above examples it appears that - boot loaders which end after 1MiB start after LBA 34; - boot loaders which start before LBA 34 end before 1MiB. So the following logic seems safe: - if FirstUsableLBA <= 1MiB, the purpose is likely to avoid interference between the boot loader and the primary PEA -> move the primary PEA just before the FirstUsableLBA; - if FirstUsableLBA > 1MiB, the purpose is likely to avoid interference between the boot loader and partitions -> leave the primary PEA just after the primary header (default). --- libparted/labels/gpt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c index 87261dbd..422720b6 100644 --- a/libparted/labels/gpt.c +++ b/libparted/labels/gpt.c @@ -1076,6 +1076,15 @@ gpt_read (PedDisk *disk) goto error_free_gpt; gpt = backup_gpt; + /* Set PrimaryPartitionEntryLBA before FirstUsableLBA if <= 1MiB */ + if ((PED_LE32_TO_CPU (gpt->FirstUsableLBA) * disk->dev->sector_size) + <= 1048576) + { + gpt_disk_data->PrimaryPartitionEntryLBA = + PED_LE32_TO_CPU (gpt->FirstUsableLBA) + - (ped_div_round_up (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries) + * sizeof(GuidPartitionEntry_t), disk->dev->sector_size)); + } } backup_gpt = NULL; primary_gpt = NULL; -- 2.39.5 From mike.fleetwood at googlemail.com Sun Nov 30 09:34:57 2025 From: mike.fleetwood at googlemail.com (Mike Fleetwood) Date: Sun, 30 Nov 2025 09:34:57 +0000 Subject: [parted-devel] [PATCH 2/2] tests: t2420: New test confirming updating msdos doesn't add boot code In-Reply-To: References: <20251024130303.8818-1-mike.fleetwood@googlemail.com> <20251024130303.8818-2-mike.fleetwood@googlemail.com> Message-ID: On Fri, 24 Oct 2025 at 23:31, Brian C. Lane wrote: > Small tweak to this, the test run with multiple sector sizes so using > sector counts in mkpart can fail because 10M isn't large enough. Just > use M instead. ... > (I've changed this locally, no need to resubmit). Is there anything more needed from me before this is committed to the parted GIT repo? Thanks, Mike