- libfdisk: improve collision reporting - libfdisk: (dos) ignore incomplete EBR for non-wholedisk - wall: always use utmp as fallback Resolves: RHEL-84815 RHEL-59867 RHEL-82162 RHEL-113639
242 lines
8.5 KiB
Diff
242 lines
8.5 KiB
Diff
From af9954b8da649684241c55fa617fdf629b33a454 Mon Sep 17 00:00:00 2001
|
|
From: Karel Zak <kzak@redhat.com>
|
|
Date: Mon, 8 Sep 2025 11:44:16 +0200
|
|
Subject: libfdisk: improve collision reporting
|
|
|
|
In some cases, a collision occurs in the first sector. Creating a new
|
|
partition table overwrites this sector, but updating an existing table
|
|
does not. In the latter case, promising to wipe the collision is a
|
|
bug.
|
|
|
|
Because we cannot know whether the collision is expected (e.g., hybrid
|
|
or boot disks) or unintended, we inform the user and let them decide.
|
|
libfdisk can wipe the unwanted signature only when creating a new
|
|
partition table; otherwise, the user can use wipefs.
|
|
|
|
This commit introduces fdisk_is_collision_area(), an API to detect
|
|
where the collision occurs. The function is generic and not limited to
|
|
the first sector.
|
|
|
|
Fixes: https://github.com/util-linux/util-linux/issues/3659
|
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
|
Upstream: http://github.com/util-linux/util-linux/commit/e873aa0322f42167a402e95dd398fcc4eb256119
|
|
Addresses: https://issues.redhat.com/browse/RHEL-82162
|
|
---
|
|
disk-utils/fdisk.c | 21 +++++++++++++++------
|
|
disk-utils/sfdisk.c | 28 +++++++++++++++++++---------
|
|
libfdisk/docs/libfdisk-sections.txt | 1 +
|
|
libfdisk/src/context.c | 21 +++++++++++++++++++++
|
|
libfdisk/src/fdiskP.h | 1 +
|
|
libfdisk/src/libfdisk.h.in | 1 +
|
|
libfdisk/src/libfdisk.sym | 4 ++++
|
|
libfdisk/src/wipe.c | 23 ++++++++++++++++-------
|
|
8 files changed, 78 insertions(+), 22 deletions(-)
|
|
|
|
diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c
|
|
index c75a7a63c..490e7b670 100644
|
|
--- a/disk-utils/fdisk.c
|
|
+++ b/disk-utils/fdisk.c
|
|
@@ -924,12 +924,21 @@ void follow_wipe_mode(struct fdisk_context *cxt)
|
|
dowipe = 1; /* always remove old PT */
|
|
|
|
fdisk_enable_wipe(cxt, dowipe);
|
|
- if (dowipe)
|
|
- fdisk_warnx(cxt, _(
|
|
- "The device contains '%s' signature and it will be removed by a write command. "
|
|
- "See fdisk(8) man page and --wipe option for more details."),
|
|
- fdisk_get_collision(cxt));
|
|
- else
|
|
+
|
|
+ if (dowipe) {
|
|
+ /* check if collision in first sector */
|
|
+ if (fdisk_has_label(cxt) && fdisk_is_collision_area(cxt, 0,
|
|
+ fdisk_get_sector_size(cxt)))
|
|
+ fdisk_warnx(cxt, _(
|
|
+ "The device contains a '%s' signature in the first sector; it will not be wiped "
|
|
+ "unless you create a new partition table. Alternatively, use wipefs(8)."),
|
|
+ fdisk_get_collision(cxt));
|
|
+ else
|
|
+ fdisk_warnx(cxt, _(
|
|
+ "The device contains '%s' signature and it will be removed by a write command. "
|
|
+ "See fdisk(8) man page and --wipe option for more details."),
|
|
+ fdisk_get_collision(cxt));
|
|
+ } else
|
|
fdisk_warnx(cxt, _(
|
|
"The device contains '%s' signature and it may remain on the device. "
|
|
"It is recommended to wipe the device with wipefs(8) or "
|
|
diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c
|
|
index d8dd8d296..b25cc7955 100644
|
|
--- a/disk-utils/sfdisk.c
|
|
+++ b/disk-utils/sfdisk.c
|
|
@@ -1661,22 +1661,32 @@ static void follow_wipe_mode(struct sfdisk *sf)
|
|
if (sf->quiet)
|
|
return;
|
|
|
|
- if (dowipe) {
|
|
- if (!fdisk_is_ptcollision(sf->cxt)) {
|
|
- fdisk_warnx(sf->cxt, _(
|
|
- "The device contains '%s' signature and it may be removed by a write command. "
|
|
- "See sfdisk(8) man page and --wipe option for more details."),
|
|
- fdisk_get_collision(sf->cxt));
|
|
- fputc('\n', stdout);
|
|
- }
|
|
- } else {
|
|
+ if (!dowipe) {
|
|
fdisk_warnx(sf->cxt, _(
|
|
"The device contains '%s' signature and it may remain on the device. "
|
|
"It is recommended to wipe the device with wipefs(8) or "
|
|
"sfdisk --wipe, in order to avoid possible collisions."),
|
|
fdisk_get_collision(sf->cxt));
|
|
fputc('\n', stderr);
|
|
+ return;
|
|
}
|
|
+
|
|
+ if (fdisk_is_ptcollision(sf->cxt))
|
|
+ return; /* PT will be replaced */
|
|
+
|
|
+ if (sf->append && fdisk_has_label(sf->cxt)
|
|
+ && fdisk_is_collision_area(sf->cxt, 0, fdisk_get_sector_size(sf->cxt)))
|
|
+ fdisk_warnx(sf->cxt, _(
|
|
+ "The device contains a '%s' signature in the first sector; it will not be wiped "
|
|
+ "unless you create a new partition table. Alternatively, use wipefs(8)."),
|
|
+ fdisk_get_collision(sf->cxt));
|
|
+ else
|
|
+ fdisk_warnx(sf->cxt, _(
|
|
+ "The device contains '%s' signature and it may be removed by a write command. "
|
|
+ "See sfdisk(8) man page and --wipe option for more details."),
|
|
+ fdisk_get_collision(sf->cxt));
|
|
+
|
|
+ fputc('\n', stdout);
|
|
}
|
|
|
|
static int wipe_partition(struct sfdisk *sf, size_t partno)
|
|
diff --git a/libfdisk/docs/libfdisk-sections.txt b/libfdisk/docs/libfdisk-sections.txt
|
|
index efc138571..1e4b82e2d 100644
|
|
--- a/libfdisk/docs/libfdisk-sections.txt
|
|
+++ b/libfdisk/docs/libfdisk-sections.txt
|
|
@@ -335,6 +335,7 @@ fdisk_has_dialogs
|
|
fdisk_has_label
|
|
fdisk_has_protected_bootbits
|
|
fdisk_has_wipe
|
|
+fdisk_is_collision_area
|
|
fdisk_is_details
|
|
fdisk_is_labeltype
|
|
fdisk_is_listonly
|
|
diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c
|
|
index 463a60f86..a9e6027ea 100644
|
|
--- a/libfdisk/src/context.c
|
|
+++ b/libfdisk/src/context.c
|
|
@@ -449,6 +449,27 @@ int fdisk_is_ptcollision(struct fdisk_context *cxt)
|
|
return cxt->pt_collision;
|
|
}
|
|
|
|
+/**
|
|
+ * fdisk_is_collision_area:
|
|
+ * @cxt: fdisk context
|
|
+ *
|
|
+ * If there is a collision with the filesystem or another partition table,
|
|
+ * verify that the detected magic string is within the specified area.
|
|
+ *
|
|
+ * Returns: 0 or 1
|
|
+ *
|
|
+ * Since: v2.42
|
|
+ */
|
|
+int fdisk_is_collision_area(struct fdisk_context *cxt,
|
|
+ uint64_t start, uint64_t size)
|
|
+{
|
|
+ if (cxt->collision &&
|
|
+ start <= cxt->collision_offset && cxt->collision_offset <= start + size)
|
|
+ return 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/**
|
|
* fdisk_get_npartitions:
|
|
* @cxt: context
|
|
diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h
|
|
index 49e057f11..84203976a 100644
|
|
--- a/libfdisk/src/fdiskP.h
|
|
+++ b/libfdisk/src/fdiskP.h
|
|
@@ -409,6 +409,7 @@ struct fdisk_context {
|
|
listonly : 1; /* list partition, nothing else */
|
|
|
|
char *collision; /* name of already existing FS/PT */
|
|
+ uint64_t collision_offset;
|
|
struct list_head wipes; /* list of areas to wipe before write */
|
|
|
|
int sizeunit; /* SIZE fields, FDISK_SIZEUNIT_* */
|
|
diff --git a/libfdisk/src/libfdisk.h.in b/libfdisk/src/libfdisk.h.in
|
|
index 9c20f44be..ccf8582ed 100644
|
|
--- a/libfdisk/src/libfdisk.h.in
|
|
+++ b/libfdisk/src/libfdisk.h.in
|
|
@@ -217,6 +217,7 @@ int fdisk_enable_wipe(struct fdisk_context *cxt, int enable);
|
|
int fdisk_has_wipe(struct fdisk_context *cxt);
|
|
const char *fdisk_get_collision(struct fdisk_context *cxt);
|
|
int fdisk_is_ptcollision(struct fdisk_context *cxt);
|
|
+int fdisk_is_collision_area(struct fdisk_context *cxt, uint64_t start, uint64_t size);
|
|
|
|
int fdisk_set_unit(struct fdisk_context *cxt, const char *str);
|
|
const char *fdisk_get_unit(struct fdisk_context *cxt, int n);
|
|
diff --git a/libfdisk/src/libfdisk.sym b/libfdisk/src/libfdisk.sym
|
|
index bb69e93c4..81049133a 100644
|
|
--- a/libfdisk/src/libfdisk.sym
|
|
+++ b/libfdisk/src/libfdisk.sym
|
|
@@ -324,3 +324,7 @@ FDISK_2.38 {
|
|
FDISK_2.40 {
|
|
fdisk_partition_get_max_size;
|
|
} FDISK_2.38;
|
|
+
|
|
+FDISK_2_42 {
|
|
+ fdisk_is_collision_area;
|
|
+} FDISK_2.40;
|
|
diff --git a/libfdisk/src/wipe.c b/libfdisk/src/wipe.c
|
|
index bb5f1bb38..48e0036bf 100644
|
|
--- a/libfdisk/src/wipe.c
|
|
+++ b/libfdisk/src/wipe.c
|
|
@@ -178,25 +178,34 @@ int fdisk_check_collisions(struct fdisk_context *cxt)
|
|
|
|
blkid_probe_enable_superblocks(pr, 1);
|
|
blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE |
|
|
+ BLKID_SUBLKS_MAGIC |
|
|
BLKID_SUBLKS_BADCSUM);
|
|
blkid_probe_enable_partitions(pr, 1);
|
|
- blkid_probe_set_partitions_flags(pr, BLKID_PARTS_FORCE_GPT);
|
|
+ blkid_probe_set_partitions_flags(pr, BLKID_PARTS_FORCE_GPT |
|
|
+ BLKID_PARTS_MAGIC);
|
|
|
|
/* we care about the first found FS/raid, so don't call blkid_do_probe()
|
|
* in loop or don't use blkid_do_fullprobe() ... */
|
|
rc = blkid_do_probe(pr);
|
|
if (rc == 0) {
|
|
const char *name = NULL;
|
|
+ const char *off = NULL;
|
|
|
|
- if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0)
|
|
- cxt->collision = strdup(name);
|
|
- else if (blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
|
|
- cxt->collision = strdup(name);
|
|
+ if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0) {
|
|
+ blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL);
|
|
+
|
|
+ } else if (blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
|
|
+ blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL);
|
|
cxt->pt_collision = 1;
|
|
}
|
|
|
|
- if (name && !cxt->collision)
|
|
- rc = -ENOMEM;
|
|
+ if (name) {
|
|
+ cxt->collision = strdup(name);
|
|
+ if (!cxt->collision)
|
|
+ rc = -ENOMEM;
|
|
+ }
|
|
+ if (!rc && off)
|
|
+ cxt->collision_offset = strtoumax(off, NULL, 10);
|
|
}
|
|
|
|
blkid_free_probe(pr);
|
|
--
|
|
2.50.1
|
|
|