The BSD, Minix, Solaris x86, and UnixWare probers cached a raw
pointer to a parent partition entry that could become stale when
the entry array was reallocated, causing a heap use-after-free
read. A crafted block device image can trigger this via
udev/udisks without user interaction.
Re-fetch the parent entry after each addition instead of caching it.

Backport patch to fix CVE-2026-13595
  https://nvd.nist.gov/vuln/detail/CVE-2026-13595

Upstream fix:
  
https://github.com/util-linux/util-linux/commit/c0186f14fbdb02f64c8e0ba701ce727ea764ff4c

Tested with ptest on QEMU x86_64:
   All 329 tests PASSED

Signed-off-by: Ravineet Singh <[email protected]>
---
 meta/recipes-core/util-linux/util-linux.inc   |   1 +
 .../util-linux/CVE-2026-13595.patch           | 145 ++++++++++++++++++
 2 files changed, 146 insertions(+)
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2026-13595.patch

diff --git a/meta/recipes-core/util-linux/util-linux.inc 
b/meta/recipes-core/util-linux/util-linux.inc
index 0235862666..2a994d7a38 100644
--- a/meta/recipes-core/util-linux/util-linux.inc
+++ b/meta/recipes-core/util-linux/util-linux.inc
@@ -21,6 +21,7 @@ SRC_URI = 
"${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin
            
file://0001-ts-kill-decode-use-RTMIN-from-kill-L-instead-of-hard.patch \
            file://0001-tests-script-Disable-size-option-test.patch \
            
file://0001-loopdev-add-LOOPDEV_FL_NOFOLLOW-to-prevent-symlink-a.patch \
+           file://CVE-2026-13595.patch \
            "
 
 SRC_URI[sha256sum] = 
"3330d873f0fceb5560b89a7dc14e4f3288bbd880e96903ed9b50ec2b5799e58b"
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2026-13595.patch 
b/meta/recipes-core/util-linux/util-linux/CVE-2026-13595.patch
new file mode 100644
index 0000000000..55d7fc9023
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2026-13595.patch
@@ -0,0 +1,145 @@
+From e35a8bd91cc1781692dbd2b542ecacb983b4776f Mon Sep 17 00:00:00 2001
+From: Karel Zak <[email protected]>
+Date: Thu, 7 May 2026 12:50:48 +0200
+Subject: [PATCH] libblkid: fix use-after-free in nested partition probing
+
+The partitions list stores partitions in a contiguous array grown by
+reallocarray(). When the array is reallocated to a new address, all
+existing blkid_partition pointers (tab->parent, ls->next_parent, local
+parent variables in nested probers) become dangling.
+
+Fix this by changing the storage from an array of structs to an array
+of pointers, where each partition is individually allocated via
+calloc(). This makes all blkid_partition pointers stable across
+reallocations -- only the pointer array itself may move, which is
+harmless since no code caches pointers into the pointer array.
+
+This eliminates the need for callers to re-fetch parent pointers after
+every blkid_partlist_add_partition() call.
+
+Reported-by: Thai Duong <[email protected]>
+Signed-off-by: Karel Zak <[email protected]>
+CVE: CVE-2026-13595
+Upstream-Status: Backport 
[https://github.com/util-linux/util-linux/commit/c0186f14fbdb02f64c8e0ba701ce727ea764ff4c]
+Signed-off-by: Ravineet Singh <[email protected]>
+---
+ libblkid/src/partitions/partitions.c | 34 +++++++++++++++++-----------
+ 1 file changed, 21 insertions(+), 13 deletions(-)
+
+diff --git a/libblkid/src/partitions/partitions.c 
b/libblkid/src/partitions/partitions.c
+index 9df813c92..e600e5e45 100644
+--- a/libblkid/src/partitions/partitions.c
++++ b/libblkid/src/partitions/partitions.c
+@@ -198,7 +198,7 @@ struct blkid_struct_partlist {
+ 
+       int             nparts;         /* number of partitions */
+       int             nparts_max;     /* max.number of partitions */
+-      blkid_partition parts;          /* array of partitions */
++      blkid_partition *parts;         /* array of pointers to partitions */
+ 
+       struct list_head l_tabs;        /* list of partition tables */
+ };
+@@ -357,13 +357,16 @@ static void reset_partlist(blkid_partlist ls)
+       free_parttables(ls);
+ 
+       if (ls->next_partno) {
+-              /* already initialized - reset */
+-              int tmp_nparts = ls->nparts_max;
+-              blkid_partition tmp_parts = ls->parts;
++              /* already initialized - free individually allocated partitions 
*/
++              int i, tmp_nparts_max = ls->nparts_max;
++              blkid_partition *tmp_parts = ls->parts;
++
++              for (i = 0; i < ls->nparts; i++)
++                      free(ls->parts[i]);
+ 
+               memset(ls, 0, sizeof(struct blkid_struct_partlist));
+ 
+-              ls->nparts_max = tmp_nparts;
++              ls->nparts_max = tmp_nparts_max;
+               ls->parts = tmp_parts;
+       }
+ 
+@@ -398,6 +401,7 @@ static void partitions_free_data(blkid_probe pr 
__attribute__((__unused__)),
+                                void *data)
+ {
+       blkid_partlist ls = (blkid_partlist) data;
++      int i;
+ 
+       if (!ls)
+               return;
+@@ -405,6 +409,8 @@ static void partitions_free_data(blkid_probe pr 
__attribute__((__unused__)),
+       free_parttables(ls);
+ 
+       /* deallocate partitions and partlist */
++      for (i = 0; i < ls->nparts; i++)
++              free(ls->parts[i]);
+       free(ls->parts);
+       free(ls);
+ }
+@@ -438,15 +444,17 @@ static blkid_partition new_partition(blkid_partlist ls, 
blkid_parttable tab)
+                * generic Linux machine -- let start with 32 partitions.
+                */
+               void *tmp = reallocarray(ls->parts, ls->nparts_max + 32,
+-                                       sizeof(struct blkid_struct_partition));
++                                       sizeof(blkid_partition));
+               if (!tmp)
+                       return NULL;
+               ls->parts = tmp;
+               ls->nparts_max += 32;
+       }
+ 
+-      par = &ls->parts[ls->nparts++];
+-      memset(par, 0, sizeof(struct blkid_struct_partition));
++      par = calloc(1, sizeof(struct blkid_struct_partition));
++      if (!par)
++              return NULL;
++      ls->parts[ls->nparts++] = par;
+ 
+       ref_parttable(tab);
+       par->tab = tab;
+@@ -851,7 +859,7 @@ int blkid_probe_is_covered_by_pt(blkid_probe pr,
+ 
+       /* check if the partition table fits into the device */
+       for (i = 0; i < nparts; i++) {
+-              blkid_partition par = &ls->parts[i];
++              blkid_partition par = ls->parts[i];
+ 
+               if (par->start + par->size > (pr->size >> 9)) {
+                       DBG(LOWPROBE, ul_debug("partition #%d overflows "
+@@ -863,7 +871,7 @@ int blkid_probe_is_covered_by_pt(blkid_probe pr,
+ 
+       /* check if the requested area is covered by PT */
+       for (i = 0; i < nparts; i++) {
+-              blkid_partition par = &ls->parts[i];
++              blkid_partition par = ls->parts[i];
+ 
+               if (start >= par->start && end <= par->start + par->size) {
+                       rc = 1;
+@@ -962,7 +970,7 @@ blkid_partition 
blkid_partlist_get_partition(blkid_partlist ls, int n)
+       if (n < 0 || n >= ls->nparts)
+               return NULL;
+ 
+-      return &ls->parts[n];
++      return ls->parts[n];
+ }
+ 
+ blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, 
uint64_t start)
+@@ -1074,7 +1082,7 @@ blkid_partition 
blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno
+                * and an entry in partition table.
+                */
+                for (i = 0; i < ls->nparts; i++) {
+-                       blkid_partition par = &ls->parts[i];
++                       blkid_partition par = ls->parts[i];
+ 
+                        if (partno != blkid_partition_get_partno(par))
+                                continue;
+@@ -1090,7 +1098,7 @@ blkid_partition 
blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno
+       DBG(LOWPROBE, ul_debug("searching by offset/size"));
+ 
+       for (i = 0; i < ls->nparts; i++) {
+-              blkid_partition par = &ls->parts[i];
++              blkid_partition par = ls->parts[i];
+ 
+               if ((uint64_t)blkid_partition_get_start(par) == start &&
+                   (uint64_t)blkid_partition_get_size(par) == size)
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#240987): 
https://lists.openembedded.org/g/openembedded-core/message/240987
Mute This Topic: https://lists.openembedded.org/mt/120284104/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to