Skip to content

Commit c8f1140

Browse files
committed
udf: Avoid invalid LVID used on mount
udf_load_logicalvolint() loads logical volume integrity descriptors. Since there can be multiple blocks with LVIDs, we verify the contents of only the last (prevailing) LVID found. However if we fail to load the last LVID (either due to IO error or because it's checksum fails to match), we never perform the verification of validity of the LVID we are going to use. If such LVID contains invalid data, we can hit out-of-bounds access or similar issues. Fix the problem by verifying each LVID we are potentially going to accept. Reported-by: Robert Morris <rtm@csail.mit.edu> Signed-off-by: Jan Kara <jack@suse.cz>
1 parent d0aa726 commit c8f1140

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

fs/udf/super.c

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,20 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
15391539
return ret;
15401540
}
15411541

1542+
static bool udf_lvid_valid(struct super_block *sb,
1543+
struct logicalVolIntegrityDesc *lvid)
1544+
{
1545+
u32 parts, impuselen;
1546+
1547+
parts = le32_to_cpu(lvid->numOfPartitions);
1548+
impuselen = le32_to_cpu(lvid->lengthOfImpUse);
1549+
if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
1550+
sizeof(struct logicalVolIntegrityDesc) + impuselen +
1551+
2 * parts * sizeof(u32) > sb->s_blocksize)
1552+
return false;
1553+
return true;
1554+
}
1555+
15421556
/*
15431557
* Find the prevailing Logical Volume Integrity Descriptor.
15441558
*/
@@ -1549,7 +1563,6 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
15491563
struct udf_sb_info *sbi = UDF_SB(sb);
15501564
struct logicalVolIntegrityDesc *lvid;
15511565
int indirections = 0;
1552-
u32 parts, impuselen;
15531566

15541567
while (++indirections <= UDF_MAX_LVID_NESTING) {
15551568
final_bh = NULL;
@@ -1571,32 +1584,27 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
15711584
if (!final_bh)
15721585
return;
15731586

1574-
brelse(sbi->s_lvid_bh);
1575-
sbi->s_lvid_bh = final_bh;
1576-
15771587
lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
1588+
if (udf_lvid_valid(sb, lvid)) {
1589+
brelse(sbi->s_lvid_bh);
1590+
sbi->s_lvid_bh = final_bh;
1591+
} else {
1592+
udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
1593+
"ignoring.\n",
1594+
le32_to_cpu(lvid->numOfPartitions),
1595+
le32_to_cpu(lvid->lengthOfImpUse));
1596+
}
1597+
15781598
if (lvid->nextIntegrityExt.extLength == 0)
1579-
goto check;
1599+
return;
15801600

15811601
loc = leea_to_cpu(lvid->nextIntegrityExt);
15821602
}
15831603

15841604
udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n",
15851605
UDF_MAX_LVID_NESTING);
1586-
out_err:
15871606
brelse(sbi->s_lvid_bh);
15881607
sbi->s_lvid_bh = NULL;
1589-
return;
1590-
check:
1591-
parts = le32_to_cpu(lvid->numOfPartitions);
1592-
impuselen = le32_to_cpu(lvid->lengthOfImpUse);
1593-
if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
1594-
sizeof(struct logicalVolIntegrityDesc) + impuselen +
1595-
2 * parts * sizeof(u32) > sb->s_blocksize) {
1596-
udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
1597-
"ignoring.\n", parts, impuselen);
1598-
goto out_err;
1599-
}
16001608
}
16011609

16021610
/*

0 commit comments

Comments
 (0)