@@ -47,6 +47,7 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin
file://CVE-2025-14104-01.patch \
file://CVE-2025-14104-02.patch \
file://CVE-2026-27456.patch \
+ file://CVE-2026-13595.patch \
"
SRC_URI[sha256sum] = "7b6605e48d1a49f43cc4b4cfc59f313d0dd5402fa40b96810bd572e167dfed0f"
new file mode 100644
@@ -0,0 +1,154 @@
+From 0bf0391bc10c04ac7fa2807d72a5f96f4b164fa5 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+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 <thaidn@gmail.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+
+CVE: CVE-2026-13595
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/c0186f14fbdb02f64c8e0ba701ce727ea764ff4c]
+Signed-off-by: Ravineet Singh <ravineet.a.singh@est.tech>
+---
+ libblkid/src/partitions/partitions.c | 38 +++++++++++++++++-----------
+ 1 file changed, 23 insertions(+), 15 deletions(-)
+
+diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
+index 1c344fd30..36e528837 100644
+--- a/libblkid/src/partitions/partitions.c
++++ b/libblkid/src/partitions/partitions.c
+@@ -197,7 +197,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 */
+ };
+@@ -356,13 +356,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;
+ }
+
+@@ -397,6 +400,7 @@ static void partitions_free_data(blkid_probe pr __attribute__((__unused__)),
+ void *data)
+ {
+ blkid_partlist ls = (blkid_partlist) data;
++ int i;
+
+ if (!ls)
+ return;
+@@ -404,6 +408,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);
+ }
+@@ -436,16 +442,19 @@ static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab)
+ /* Linux kernel has DISK_MAX_PARTS=256, but it's too much for
+ * generic Linux machine -- let start with 32 partitions.
+ */
+- void *tmp = realloc(ls->parts, (ls->nparts_max + 32) *
+- sizeof(struct blkid_struct_partition));
++ void *tmp = reallocarray(ls->parts, ls->nparts_max + 32,
++ 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;
+@@ -848,7 +857,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 "
+@@ -860,7 +869,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;
+@@ -959,7 +968,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)
+@@ -1071,7 +1080,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;
+@@ -1087,7 +1096,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)
+@@ -1528,4 +1537,3 @@ unsigned long long blkid_partition_get_flags(blkid_partition par)
+ {
+ return par->flags;
+ }
+-
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 256 tests PASSED Signed-off-by: Ravineet Singh <ravineet.a.singh@est.tech> --- meta/recipes-core/util-linux/util-linux.inc | 1 + .../util-linux/CVE-2026-13595.patch | 154 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2026-13595.patch