]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: fix OOM on GPT with huge partition entries array
authorKarel Zak <kzak@redhat.com>
Mon, 22 Jun 2026 08:25:12 +0000 (10:25 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 22 Jun 2026 08:25:12 +0000 (10:25 +0200)
Add sanity checks to gpt_read_entries() to prevent out-of-memory when
reading a crafted GPT header with an absurdly large npartition_entries
value. The entries array size is now limited by:

 - GPT_NPARTITIONS_MAX hard cap (~4MiB)
 - first_usable_lba, since entries must fit before the first usable sector

Also reorder validation in gpt_read_header() to perform all cheap
header-only checks (my_lba, LBA sanity) before attempting to allocate
and read the entries array.

Addresses: https://github.com/util-linux/util-linux/issues/4432
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/gpt.c

index b985f087a640d514f68135358a89f85adc28091e..a2a9314c32beec9bd42db7f9f2ace152fcdda416 100644 (file)
@@ -52,6 +52,7 @@
 #define MSDOS_MBR_SIGNATURE 0xAA55
 #define GPT_PART_NAME_LEN   (72 / sizeof(uint16_t))
 #define GPT_NPARTITIONS     ((size_t) FDISK_GPT_NPARTITIONS_DEFAULT)
+#define GPT_NPARTITIONS_MAX (4 * 1024 * 1024 / sizeof(struct gpt_entry))
 
 /* Globally unique identifier */
 struct gpt_guid {
@@ -1019,6 +1020,11 @@ static unsigned char *gpt_read_entries(struct fdisk_context *cxt,
 
        if (gpt_sizeof_entries(header, &sz))
                return NULL;
+       if (sz > GPT_NPARTITIONS_MAX * sizeof(struct gpt_entry)
+           || sz / cxt->sector_size >= le64_to_cpu(header->first_usable_lba)) {
+               DBG(GPT, ul_debug("entries array too large"));
+               return NULL;
+       }
 
        ret = calloc(1, sz);
        if (!ret)
@@ -1198,10 +1204,17 @@ static struct gpt_header *gpt_read_header(struct fdisk_context *cxt,
        if (!gpt_check_header_crc(header, NULL))
                goto invalid;
 
+       /* valid header must be at MyLBA */
+       if (le64_to_cpu(header->my_lba) != lba)
+               goto invalid;
+
        /* entry size must be large enough to hold struct gpt_entry */
        if (le32_to_cpu(header->sizeof_partition_entry) < sizeof(struct gpt_entry))
                goto invalid;
 
+       if (!gpt_check_lba_sanity(cxt, header))
+               goto invalid;
+
        /* read and verify entries */
        ents = gpt_read_entries(cxt, header);
        if (!ents)
@@ -1210,13 +1223,6 @@ static struct gpt_header *gpt_read_header(struct fdisk_context *cxt,
        if (!gpt_check_entryarr_crc(header, ents))
                goto invalid;
 
-       if (!gpt_check_lba_sanity(cxt, header))
-               goto invalid;
-
-       /* valid header must be at MyLBA */
-       if (le64_to_cpu(header->my_lba) != lba)
-               goto invalid;
-
        if (_ents)
                *_ents = ents;
        else