* [PATCH] libblkid: avoid undefined shifts and an unaligned read in the probes
@ 2026-09-21 16:29 Akira Patafio
0 siblings, 0 replies; only message in thread
From: Akira Patafio @ 2026-09-21 16:29 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: linux-ext4
Three sites in lib/blkid/probe.c operate on values taken straight from a
superblock, which on any system that probes removable media is
attacker-supplied.
probe_jfs() uses js_l2bsize and js_l2pbsize as shift exponents on a
32-bit 1U. Both are 16-bit on-disk fields, so any value of 32 or more
makes the shift undefined. No such value can describe a valid 32-bit
block size, so reject the superblock rather than shift by it.
exfat_next_cluster() casts the result of get_buffer() to uint32_t * and
dereferences it. get_buffer() returns a pointer into a byte buffer at an
offset computed from fat_block_start, so it carries no alignment
guarantee and the offset is under the volume's control; the dereference
is undefined when that offset is not 4-byte aligned. Copy the bytes out
with memcpy() instead, which the compiler turns back into a load where
unaligned access is permitted.
Neither has a memory-safety consequence: the shifts only produce a wrong
comparison, and get_buffer() already bounds-checks the read it returns.
This is a correctness and undefined-behaviour fix.
Found with libFuzzer and UBSan (clang 18, aarch64) over a corpus of
NTFS/exFAT/JFS superblocks. util-linux made equivalent changes to its
fork of this code in 585815c1f8f7 ("libblkid: exfat - avoid undefined
shift") and 9c82a8ca123a ("libblkid: ntfs: avoid UB in signed shift").
Signed-off-by: Akira Patafio <kokokoala4211@gmail.com>
---
lib/blkid/probe.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c
index 6a3bb24..689ee6d 100644
--- a/lib/blkid/probe.c
+++ b/lib/blkid/probe.c
@@ -854,13 +854,16 @@ static int probe_jfs(struct blkid_probe *probe,
{
struct jfs_super_block *js;
const char *label = 0;
+ uint16_t l2bsize, l2pbsize;
js = (struct jfs_super_block *)buf;
- if (blkid_le32(js->js_bsize) != (1U << blkid_le16(js->js_l2bsize)))
+ l2bsize = blkid_le16(js->js_l2bsize);
+ if (l2bsize >= 32 || blkid_le32(js->js_bsize) != (1U << l2bsize))
return 1;
- if (blkid_le32(js->js_pbsize) != (1U << blkid_le16(js->js_l2pbsize)))
+ l2pbsize = blkid_le16(js->js_l2pbsize);
+ if (l2pbsize >= 32 || blkid_le32(js->js_pbsize) != (1U << l2pbsize))
return 1;
if ((blkid_le16(js->js_l2bsize) - blkid_le16(js->js_l2pbsize)) !=
@@ -1461,14 +1464,19 @@ static uint32_t exfat_next_cluster(struct blkid_probe *probe,
const struct exfat_super_block *sb,
uint32_t cluster)
{
- uint32_t *next;
+ uint32_t next;
uint64_t offset;
+ unsigned char *buf;
offset = exfat_block_to_offset(sb, sb->fat_block_start)
+ (uint64_t) cluster * sizeof (cluster);
- next = (uint32_t *)get_buffer(probe, offset, sizeof (uint32_t));
+ buf = get_buffer(probe, offset, sizeof (uint32_t));
+ if (!buf)
+ return 0;
- return next ? *next : 0;
+ memcpy(&next, buf, sizeof(next));
+
+ return next;
}
static struct exfat_entry_label *find_exfat_entry_label(
--
2.50.1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-21 16:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21 16:29 [PATCH] libblkid: avoid undefined shifts and an unaligned read in the probes Akira Patafio
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox