From: Jamie Magee Date: Sat, 2 May 2026 05:00:43 +0000 (-0700) Subject: libfdisk: gpt: accept numeric attribute bits 0-2 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=3ea35fa75f20e6c99a073660d807ccc7fa25086d;p=thirdparty%2Futil-linux.git libfdisk: gpt: accept numeric attribute bits 0-2 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 accepts {0,1,2} or [48,63]; - GUID: 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 ",GUID:", 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 --- diff --git a/disk-utils/sfdisk.8.adoc b/disk-utils/sfdisk.8.adoc index 379dd46dee..9d6307634b 100644 --- a/disk-utils/sfdisk.8.adoc +++ b/disk-utils/sfdisk.8.adoc @@ -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. diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c index 27f6bd6aec..1c98d859ec 100644 --- a/libfdisk/src/gpt.c +++ b/libfdisk/src/gpt.c @@ -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: as well as */ + /* GUID: as well as . 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 index 0000000000..3984a131c6 --- /dev/null +++ b/tests/expected/sfdisk/gpt-attrs-numeric-hex @@ -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 index 0000000000..e69de29bb2 diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-mixed b/tests/expected/sfdisk/gpt-attrs-numeric-mixed new file mode 100644 index 0000000000..5c3c324fe6 --- /dev/null +++ b/tests/expected/sfdisk/gpt-attrs-numeric-mixed @@ -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 index 0000000000..e69de29bb2 diff --git a/tests/expected/sfdisk/gpt-attrs-numeric-named b/tests/expected/sfdisk/gpt-attrs-numeric-named new file mode 100644 index 0000000000..529c2b0b27 --- /dev/null +++ b/tests/expected/sfdisk/gpt-attrs-numeric-named @@ -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 index 0000000000..e69de29bb2 diff --git a/tests/expected/sfdisk/gpt-attrs-reserved b/tests/expected/sfdisk/gpt-attrs-reserved new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/sfdisk/gpt-attrs-reserved.err b/tests/expected/sfdisk/gpt-attrs-reserved.err new file mode 100644 index 0000000000..d6ee575225 --- /dev/null +++ b/tests/expected/sfdisk/gpt-attrs-reserved.err @@ -0,0 +1,2 @@ +unsupported GPT attribute bit '5' +sfdisk: : partition 2: failed to set partition attributes diff --git a/tests/ts/sfdisk/gpt b/tests/ts/sfdisk/gpt index 9b0d78de53..10290485bc 100755 --- a/tests/ts/sfdisk/gpt +++ b/tests/ts/sfdisk/gpt @@ -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