mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 05:32:00 +00:00
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>
This commit is contained in:
parent
d0aa72604f
commit
c8f1140cb8
@ -1539,6 +1539,20 @@ out_bh:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool udf_lvid_valid(struct super_block *sb,
|
||||||
|
struct logicalVolIntegrityDesc *lvid)
|
||||||
|
{
|
||||||
|
u32 parts, impuselen;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the prevailing Logical Volume Integrity Descriptor.
|
* Find the prevailing Logical Volume Integrity Descriptor.
|
||||||
*/
|
*/
|
||||||
@ -1549,7 +1563,6 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
|
|||||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||||
struct logicalVolIntegrityDesc *lvid;
|
struct logicalVolIntegrityDesc *lvid;
|
||||||
int indirections = 0;
|
int indirections = 0;
|
||||||
u32 parts, impuselen;
|
|
||||||
|
|
||||||
while (++indirections <= UDF_MAX_LVID_NESTING) {
|
while (++indirections <= UDF_MAX_LVID_NESTING) {
|
||||||
final_bh = NULL;
|
final_bh = NULL;
|
||||||
@ -1571,32 +1584,27 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
|
|||||||
if (!final_bh)
|
if (!final_bh)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
brelse(sbi->s_lvid_bh);
|
|
||||||
sbi->s_lvid_bh = final_bh;
|
|
||||||
|
|
||||||
lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
|
lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
|
||||||
|
if (udf_lvid_valid(sb, lvid)) {
|
||||||
|
brelse(sbi->s_lvid_bh);
|
||||||
|
sbi->s_lvid_bh = final_bh;
|
||||||
|
} else {
|
||||||
|
udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
|
||||||
|
"ignoring.\n",
|
||||||
|
le32_to_cpu(lvid->numOfPartitions),
|
||||||
|
le32_to_cpu(lvid->lengthOfImpUse));
|
||||||
|
}
|
||||||
|
|
||||||
if (lvid->nextIntegrityExt.extLength == 0)
|
if (lvid->nextIntegrityExt.extLength == 0)
|
||||||
goto check;
|
return;
|
||||||
|
|
||||||
loc = leea_to_cpu(lvid->nextIntegrityExt);
|
loc = leea_to_cpu(lvid->nextIntegrityExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n",
|
udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n",
|
||||||
UDF_MAX_LVID_NESTING);
|
UDF_MAX_LVID_NESTING);
|
||||||
out_err:
|
|
||||||
brelse(sbi->s_lvid_bh);
|
brelse(sbi->s_lvid_bh);
|
||||||
sbi->s_lvid_bh = NULL;
|
sbi->s_lvid_bh = NULL;
|
||||||
return;
|
|
||||||
check:
|
|
||||||
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) {
|
|
||||||
udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
|
|
||||||
"ignoring.\n", parts, impuselen);
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user