]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: gpt: accept numeric attribute bits 0-2
authorJamie Magee <jamie.magee@gmail.com>
Sat, 2 May 2026 05:00:43 +0000 (22:00 -0700)
committerJamie Magee <jamie.magee@gmail.com>
Sat, 2 May 2026 05:25:49 +0000 (22:25 -0700)
gpt_entry_attrs_from_string() applied the GUID-specific range check
(48-63) to every numeric input. As a result, bare numeric bits 0, 1
and 2 were silently rejected. Those bits are RequiredPartition,
NoBlockIOProtocol and LegacyBIOSBootable, so the only way to set
them was by name.

That trips up any tool that emits attributes as a numeric list.
systemd-repart, for instance, formats Flags= as a comma-separated
list of decimal bit numbers, so Flags=0x4 (LegacyBIOSBootable) was
silently lost.

Split the numeric validation by source token:

  - bare <bit> accepts {0,1,2} or [48,63];
  - GUID:<bit> stays at [48,63]; the GUID: prefix belongs to the
    GUID-specific range only;
  - bits 3-47 are still rejected (UEFI-reserved).

Two drive-by fixes in the same block:

  - 'end == str' compared strtol's end pointer to the function's
    input rather than the current parse position; replace with
    'end == p'.
  - The diagnostic for an unsupported numeric bit printed p after
    the GUID: strip, so "GUID:5" came out as "5". Save the token
    start and pass that to fdisk_warnx().

Tests cover the new accepted forms (bare 0-2, mixed "<n>,GUID:<m>",
hex) and the still-rejected reserved range.

Fixes: https://github.com/util-linux/util-linux/issues/3353
Reference: https://github.com/systemd/systemd/issues/35591
Signed-off-by: Jamie Magee <jamie.magee@gmail.com>
disk-utils/sfdisk.8.adoc
libfdisk/src/gpt.c
tests/expected/sfdisk/gpt-attrs-numeric-hex [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-numeric-hex.err [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-numeric-mixed [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-numeric-mixed.err [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-numeric-named [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-numeric-named.err [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-reserved [new file with mode: 0644]
tests/expected/sfdisk/gpt-attrs-reserved.err [new file with mode: 0644]
tests/ts/sfdisk/gpt

index 379dd46deeb1f6d3db653ef7969824bdc02503a2..9d6307634b152e87b94f978db8690bab57bba188 100644 (file)
@@ -92,7 +92,7 @@ List the partitions of all or the specified devices. This command can be used to
 List the free unpartitioned areas on all or the specified devices.
 
 *--part-attrs* _device partition-number_ [__attributes__]::
-Change the GPT partition attribute bits. If _attributes_ is not specified, then print the current partition settings. The _attributes_ argument is a comma- or space-delimited list of bits numbers or bit names. For example, the string "RequiredPartition,50,51" sets three bits. The currently supported attribute bits are:
+Change the GPT partition attribute bits. If _attributes_ is not specified, then print the current partition settings. The _attributes_ argument is a comma- or space-delimited list of bits numbers or bit names. For example, the string "RequiredPartition,50,51" sets three bits. Bit numbers may be given in decimal, octal, or hexadecimal (for example "0x2" is equivalent to "2" or "LegacyBIOSBootable"). The currently supported attribute bits are:
 +
 *Bit 0 (RequiredPartition)*;;
 If this bit is set, the partition is required for the platform to function. The creator of the partition indicates that deletion or modification of the contents can result in loss of platform features or failure for the platform to boot or operate. The system cannot function normally if this partition is removed, and it should be considered part of the hardware of the system.
@@ -103,7 +103,7 @@ The partition may be bootable by legacy BIOS firmware.
 *Bits 3-47*;;
 Undefined and must be zero. Reserved for expansion by future versions of the UEFI specification.
 *Bits 48-63*;;
-Reserved for GUID specific use. The use of these bits will vary depending on the partition type. For example Microsoft uses bit 60 to indicate read-only, 61 for shadow copy of another partition, 62 for hidden partitions and 63 to disable automount.
+Reserved for GUID specific use. The use of these bits will vary depending on the partition type. For example Microsoft uses bit 60 to indicate read-only, 61 for shadow copy of another partition, 62 for hidden partitions and 63 to disable automount. The "GUID:" prefix (e.g. "GUID:60") is accepted for these bits but is restricted to the 48-63 range.
 
 *--part-label* _device partition-number_ [__label__]::
 Change the GPT partition name (label). If _label_ is not specified, then print the current partition label.
index 27f6bd6aec93544664bc3ccdd7d615df8e86ac21..1c98d859ecac47e4b9ee75d858e2150f3ffe2289 100644 (file)
@@ -1818,11 +1818,13 @@ static int gpt_entry_attrs_from_string(
 
        while (p && *p) {
                int bit = -1;
+               const char *item;
 
                while (isblank(*p)) p++;
                if (!*p)
                        break;
 
+               item = p;
                DBG(GPT, ul_debug(" item '%s'", p));
 
                if (strncmp(p, GPT_ATTRSTR_REQ,
@@ -1842,27 +1844,35 @@ static int gpt_entry_attrs_from_string(
                        bit = GPT_ATTRBIT_NOBLOCK;
                        p += sizeof(GPT_ATTRSTR_NOBLOCK) - 1;
 
-               /* GUID:<bit> as well as <bit> */
+               /* GUID:<bit> as well as <bit>. Bare numeric input accepts
+                * the named-flag bits (0..2) and the GUID-specific range
+                * (48..63). The GUID: prefix is the documented namespace
+                * for 48..63 only. Bits 3..47 are reserved by UEFI. */
                } else if (isdigit((unsigned char) *p)
                           || (strncmp(p, "GUID:", 5) == 0
                               && isdigit((unsigned char) *(p + 5)))) {
                        char *end = NULL;
+                       int is_guid = (*p == 'G');
 
-                       if (*p == 'G')
+                       if (is_guid)
                                p += 5;
 
                        errno = 0;
                        bit = strtol(p, &end, 0);
-                       if (errno || !end || end == str
-                           || bit < GPT_ATTRBIT_GUID_FIRST
-                           || bit >= GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT)
+                       if (errno || !end || end == p)
                                bit = -1;
-                       else
+                       else if (bit >= GPT_ATTRBIT_GUID_FIRST
+                                && bit < GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT)
+                               p = end;
+                       else if (!is_guid && bit >= GPT_ATTRBIT_REQ
+                                && bit <= GPT_ATTRBIT_LEGACY)
                                p = end;
+                       else
+                               bit = -1;
                }
 
                if (bit < 0) {
-                       fdisk_warnx(cxt, _("unsupported GPT attribute bit '%s'"), p);
+                       fdisk_warnx(cxt, _("unsupported GPT attribute bit '%s'"), item);
                        return -EINVAL;
                }
 
diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-hex b/tests/expected/sfdisk/gpt-attrs-numeric-hex
new file mode 100644 (file)
index 0000000..3984a13
--- /dev/null
@@ -0,0 +1,5 @@
+
+The partition table has been altered.
+Calling ioctl() to re-read partition table.
+Syncing disks.
+LegacyBIOSBootable
diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-hex.err b/tests/expected/sfdisk/gpt-attrs-numeric-hex.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-mixed b/tests/expected/sfdisk/gpt-attrs-numeric-mixed
new file mode 100644 (file)
index 0000000..5c3c324
--- /dev/null
@@ -0,0 +1,5 @@
+
+The partition table has been altered.
+Calling ioctl() to re-read partition table.
+Syncing disks.
+LegacyBIOSBootable GUID:60
diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-mixed.err b/tests/expected/sfdisk/gpt-attrs-numeric-mixed.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-named b/tests/expected/sfdisk/gpt-attrs-numeric-named
new file mode 100644 (file)
index 0000000..529c2b0
--- /dev/null
@@ -0,0 +1,5 @@
+
+The partition table has been altered.
+Calling ioctl() to re-read partition table.
+Syncing disks.
+RequiredPartition NoBlockIOProtocol LegacyBIOSBootable
diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-named.err b/tests/expected/sfdisk/gpt-attrs-numeric-named.err
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/expected/sfdisk/gpt-attrs-reserved b/tests/expected/sfdisk/gpt-attrs-reserved
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/expected/sfdisk/gpt-attrs-reserved.err b/tests/expected/sfdisk/gpt-attrs-reserved.err
new file mode 100644 (file)
index 0000000..d6ee575
--- /dev/null
@@ -0,0 +1,2 @@
+unsupported GPT attribute bit '5'
+sfdisk: <removed>: partition 2: failed to set partition attributes
index 9b0d78de535622d79e1b373770bb9d966a5bac4f..10290485bc86872d83f14c6cce0b4d790d2e2590 100755 (executable)
@@ -130,6 +130,36 @@ ts_fdisk_clean $TS_DEVICE
 ts_finalize_subtest
 
 
+ts_init_subtest "attrs-numeric-named"
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 "0,1,2" >> $TS_OUTPUT 2>> $TS_ERRLOG
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 >> $TS_OUTPUT 2>> $TS_ERRLOG
+ts_fdisk_clean $TS_DEVICE
+udevadm settle
+ts_finalize_subtest
+
+
+ts_init_subtest "attrs-numeric-mixed"
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 "2,GUID:60" >> $TS_OUTPUT 2>> $TS_ERRLOG
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 >> $TS_OUTPUT 2>> $TS_ERRLOG
+ts_fdisk_clean $TS_DEVICE
+udevadm settle
+ts_finalize_subtest
+
+
+ts_init_subtest "attrs-numeric-hex"
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 "0x2" >> $TS_OUTPUT 2>> $TS_ERRLOG
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 >> $TS_OUTPUT 2>> $TS_ERRLOG
+ts_fdisk_clean $TS_DEVICE
+udevadm settle
+ts_finalize_subtest
+
+
+ts_init_subtest "attrs-reserved"
+$TS_CMD_SFDISK --part-attrs ${TS_DEVICE} 2 "5" >> $TS_OUTPUT 2>> $TS_ERRLOG
+ts_fdisk_clean $TS_DEVICE
+ts_finalize_subtest
+
+
 ts_init_subtest "read-dump"
 $TS_CMD_WIPEFS -a ${TS_DEVICE} &> /dev/null
 udevadm settle