ANT-2026-ZRDQDR79 · util-linux/util-linux

use-after-free medium

CVE-2026-13595 GHSA-qpmf-9p9c-455w

Severity Claude critical · Security research firm high · Maintainer medium

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Calif.

ANT-2026-ZRDQDR79: Heap-use-after-free in blkid_partition_get_start at partitions.c:1447 via nested BSD disklabel in DOS partition table

A heap-use-after-free (READ) was detected in util-linux's libblkid library through the OSS-Fuzz test-blkid-fuzz harness. libblkid handles probing of block device content types (filesystem superblocks, partition tables) and is invoked by blkid, udev, and automount infrastructure. An attacker who can present a crafted block device image to the system — via USB insertion, virtual disk attachment, or placing a disk image where automounting will scan it — can trigger the read of freed memory during probing. The READ-type UAF most likely yields information disclosure or denial of service, with code execution possible but harder given heap layout dependencies.

Target

Project: util-linux
Location: blkid_partition_get_start() at libblkid/src/partitions/partitions.c:1447

Technical Details

ASAN reports a READ-type heap-use-after-free during libblkid's probing of a crafted input, indicating internal probing data structures are freed and then accessed again. No specific ASAN size/address line or stack frames were provided in the report; the root-cause function and exact freed object are not identified. ASAN READ heap-UAF detections are highly reliable with near-zero false-positive rates due to precise allocator instrumentation.

Crash trace (truncated — full trace in attached crash.log):

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2157158283
INFO: Loaded 1 modules   (9192 inline 8-bit counters): 9192 [0x568d75257fc8, 0x568d7525a3b0), 
INFO: Loaded 1 PC tables (9192 PCs): 9192 [0x568d7525a3b0,0x568d7527e230), 
/out/test_blkid_fuzz: Running 1 inputs 1 time(s) each.
Running: /tmp/poc
EXIT_CODE:1


=== ASAN Report ===
=================================================================
==27==ERROR: AddressSanitizer: heap-use-after-free on address 0x75a1663e0200 at pc 0x568d75141f54 bp 0x7fff11ca9940 sp 0x7fff11ca9938
READ of size 8 at 0x75a1663e0200 thread T0
    #0 0x568d75141f53 in blkid_partition_get_start /src/util-linux/libblkid/src/partitions/partitions.c:1447:28
    #1 0x568d7517ea47 in probe_bsd_pt /src/util-linux/libblkid/src/partitions/bsd.c:132:17
    #2 0x568d751428a7 in idinfo_probe /src/util-linux/libblkid/src/partitions/partitions.c:560:8
    #3 0x568d751422f8 in blkid_partitions_do_subprobe /src/util-linux/libblkid/src/partitions/partitions.c:719:7
    #4 0x568d75180320 in probe_dos_pt /src/util-linux/libblkid/src/partitions/dos.c:342:10
    #5 0x568d751428a7 in idinfo_probe /src/util-linux/libblkid/src/partitions/partitions.c:560:8
    #6 0x568d751403a6 in partitions_probe /src/util-linux/libblkid/src/partitions/partitions.c:620:8
    #7 0x568d7512ff22 in blkid_probe_get_binary_data /src/util-linux/libblkid/src/probe.c:391:7
    [... 60 more frames — full trace in crash.log]

Reproduction

  1. Craft a malicious filesystem/partition image that triggers the UAF code path in libblkid probing
  2. Present the image to the target: insert USB storage, attach a virtual disk, or place the image where automount infrastructure scans it
  3. libblkid (invoked by blkid/udev/udisks, typically as root) probes the device and reads freed heap memory
  4. Result: crash (DoS), potential information disclosure, or — with favorable heap layout and chaining — possible escalation

[No reproducer or sanitizer output attached — request from security-cvd@anthropic.com if needed.]

Acknowledgement

This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-ZRDQDR79.


Reference: ANT-2026-ZRDQDR79
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Calif.

Verdict
true positive
Severity
high
UPSTREAM FIX

The change that resolved this finding.

diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
index f95fe898f33..a428c6d6c16 100644
--- a/libblkid/src/partitions/partitions.c
+++ b/libblkid/src/partitions/partitions.c
@@ -199,7 +199,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 */
 };
@@ -358,13 +358,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;
 	}
 
@@ -399,6 +402,7 @@ static void partitions_free_data(blkid_probe pr __attribute__((__unused__)),
 				 void *data)
 {
 	blkid_partlist ls = (blkid_partlist) data;
+	int i;
 
 	if (!ls)
 		return;
@@ -406,6 +410,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);
 }
@@ -439,15 +445,17 @@ static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab)
 		 * generic Linux machine -- let's 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;
@@ -852,7 +860,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 "
@@ -864,7 +872,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;
@@ -963,7 +971,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)
@@ -1075,7 +1083,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;
@@ -1091,7 +1099,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)

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

ADVISORY

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

TIMELINE

Dates from discovery through public reveal.

  1. 2026-03-20 Reported to tracker
  2. 2026-05-08 Sent to maintainer
  3. 2026-05-09 Maintainer acknowledged
  4. 2026-06-16 Patch released
  5. 2026-08-17 Publicly revealed
PROVENANCE

SHA-3-512 hash:

b322f519496ca8294ecf2a7fb53c3196ba0c9377d8c9ea3292509a123e5a32feecfbb9abdf3d4a533628cf09218b84e43bf768ae3dd331c5fbcb96e4aecf000b

Committed 2026-05-08 00:11 PT

Revealed 2026-08-17 10:47 PT

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-ZRDQDR79",
  "bug_class": "heap-use-after-free",
  "claude_severity": "critical",
  "commit_sha": null,
  "created_at": "2026-03-20T19:13:36+00:00",
  "description": "A heap-use-after-free (READ) was detected in util-linux's libblkid library through the OSS-Fuzz test-blkid-fuzz harness. libblkid handles probing of block device content types (filesystem superblocks, partition tables) and is invoked by blkid, udev, and automount infrastructure. An attacker who can present a crafted block device image to the system — via USB insertion, virtual disk attachment, or placing a disk image where automounting will scan it — can trigger the read of freed memory during probing. The READ-type UAF most likely yields information disclosure or denial of service, with code execution possible but harder given heap layout dependencies.",
  "discovered_at": null,
  "location": "blkid_partition_get_start() at libblkid/src/partitions/partitions.c:1447",
  "poc_sha256": "f013a9bb91af93bb8e505dad1e48b271ddade3e924c1192cc8c6cb49dc7d93d9",
  "preimage_version": 1,
  "project": "util-linux",
  "reproduction": [
    "Craft a malicious filesystem/partition image that triggers the UAF code path in libblkid probing",
    "Present the image to the target: insert USB storage, attach a virtual disk, or place the image where automount infrastructure scans it",
    "libblkid (invoked by blkid/udev/udisks, typically as root) probes the device and reads freed heap memory",
    "Result: crash (DoS), potential information disclosure, or — with favorable heap layout and chaining — possible escalation"
  ],
  "technical_details": "ASAN reports a READ-type heap-use-after-free during libblkid's probing of a crafted input, indicating internal probing data structures are freed and then accessed again. No specific ASAN size/address line or stack frames were provided in the report; the root-cause function and exact freed object are not identified. ASAN READ heap-UAF detections are highly reliable with near-zero false-positive rates due to precise allocator instrumentation.",
  "title": "Heap-use-after-free in blkid_partition_get_start at partitions.c:1447 via nested BSD disklabel in DOS partition table",
  "vendor_severity": "high"
}