[BUG] udf: KASAN use-after-free in udf_fill_super on crafted LVID

From: yangguikun

Date: Tue Oct 20 2026 - 04:36:30 EST


Hi Jan,

Mounting a crafted UDF image gives a KASAN use-after-free in
udf_fill_super(), before any file operation:

BUG: KASAN: use-after-free in udf_fill_super+0x1ce4/0x1e10
Read of size 2 at addr ... by task mount
Call Trace:
udf_fill_super
get_tree_bdev_flags
path_mount
__x64_sys_mount

Kernel panic - not syncing: KASAN: panic_on_warn set ...

The root cause is that udf_lvid_valid() bounds-checks the start of the
implementation-use area but not the size of the structure read from it.

static bool udf_lvid_valid(struct super_block *sb,
struct logicalVolIntegrityDesc *lvid)
{
parts = le32_to_cpu(lvid->numOfPartitions);
impuselen = le32_to_cpu(lvid->lengthOfImpUse);
if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
sizeof(struct logicalVolIntegrityDesc) + impuselen +
2 * parts * sizeof(u32) > sb->s_blocksize)
return false;
return true;
}

struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
{
partnum = le32_to_cpu(lvid->numOfPartitions);
offset = partnum * 2 * sizeof(uint32_t);
return (void *)(((uint8_t *)(lvid + 1)) + offset);
}

With blocksize = 2048, numOfPartitions = 246 and lengthOfImpUse = 0,
the check computes 80 + 0 + 1968 = 2048 and passes, while
udf_sb_lvidiu() returns lvid + 2048, i.e. exactly the end of the
block. udf_fill_super() then reads lvidiu->minUDFReadRev at +40,
which is past the buffer. Placing the LVID in the last block of the
image moves that read past the end of the file.

Reproducer

An 80 KiB image. The generator writes:

- VRS at offset 32768 (BEA01/NSR02/TEA01)
- AVDP, PVD, LVD, USD, IUVD, PD, TD
- the LVID as the last block, with numOfPartitions = 246 and
lengthOfImpUse = 0

Mount with:

mount -t udf -o loop,ro udf_lvid_oob.img /mnt

The crash is immediate; no other access is needed.

The image is included below, base64-encoded gzip. Decode with:

base64 -d udf_lvid_oob.b64 | gunzip > udf_lvid_oob.img
mount -t udf -o loop,ro udf_lvid_oob.img /mnt

udf_lvid_oob.b64:

H4sICKsg12oCA3VkZl9sdmlkX29vYi5pbWcA7d2/btNAHAfwswu9MCD6COZfi8oSsjCwEGiRiqJW
akIXpi5AJUgZQOI54BGYeAAW3oJHYGFh8YCY+dlNpFYIFRWkhubzOSnWxbZ0/nn43lmWnBIAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkO6t97u3CnUAgHmyOdzu9uQ/AMyVkfU/AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAHKdIZfoQv++/1blq+wcuPVp7MNjZWPvNablIB61UQgD47yxG
gj+LHH/7sc6Xo/8v8nypmTiM1oej07mkTrSUVreGo34Vs5jq/v6Ll8/3dsevmp1lsTA9Kl05UofJ
3Ge1OWWwU22Mn+wf2l/OyieSY9wrzVgXfbMZgJPLkfi7kXzfH9a5ycOFaQ521AYAzqpzkf+fIvGf
9up8te0fvwa+ONgbv35zakM+764BwN+Gadmu+N/F+v/aJFzbmL+5Odzu9n45flaeg0+HceMP5isA
wFGdyP+VNk3rfF05AGAulNG+RP7feVyl5eaPuylVh7cAwJlzIfK/F/l/+3Odm/fK09LXXJzgufmP
ybYPAMy8n4I53nYAQAEA

Fix

Check the size of the structure that is read afterwards:

--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1619,7 +1619,8 @@ static bool udf_lvid_valid(struct super_block *sb,
impuselen = le32_to_cpu(lvid->lengthOfImpUse);
if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
sizeof(struct logicalVolIntegrityDesc) + impuselen +
- 2 * parts * sizeof(u32) > sb->s_blocksize)
+ 2 * parts * sizeof(u32) +
+ sizeof(struct logicalVolIntegrityDescImpUse) > sb->s_blocksize)
return false;
return true;
}

With this applied the same image is rejected and mount fails with
-EINVAL; no KASAN report.

Tested on 7.3-rc7. The same image also crashes 7.2-rc5.

Found by syzkaller-style fuzzing of mounted filesystem images.

Signed-off-by: yangguikun <yangguikun19@xxxxxx>