udf: Check LVID earlier
[ Upstream commit 781d2a9a2fc7d0be53a072794dc03ef6de770f3d ] We were checking validity of LVID entries only when getting implementation use information from LVID in udf_sb_lvidiu(). However if the LVID is suitably corrupted, it can cause problems also to code such as udf_count_free() which doesn't use udf_sb_lvidiu(). So check validity of LVID already when loading it from the disk and just disable LVID altogether when it is not valid. Reported-by: syzbot+7fbfe5fed73ebb675748@syzkaller.appspotmail.com Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
cc608af36e
commit
86987cf0fb
|
@ -108,16 +108,10 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
|
||||||
return NULL;
|
return NULL;
|
||||||
lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data;
|
lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data;
|
||||||
partnum = le32_to_cpu(lvid->numOfPartitions);
|
partnum = le32_to_cpu(lvid->numOfPartitions);
|
||||||
if ((sb->s_blocksize - sizeof(struct logicalVolIntegrityDescImpUse) -
|
|
||||||
offsetof(struct logicalVolIntegrityDesc, impUse)) /
|
|
||||||
(2 * sizeof(uint32_t)) < partnum) {
|
|
||||||
udf_err(sb, "Logical volume integrity descriptor corrupted "
|
|
||||||
"(numOfPartitions = %u)!\n", partnum);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* The offset is to skip freeSpaceTable and sizeTable arrays */
|
/* The offset is to skip freeSpaceTable and sizeTable arrays */
|
||||||
offset = partnum * 2 * sizeof(uint32_t);
|
offset = partnum * 2 * sizeof(uint32_t);
|
||||||
return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]);
|
return (struct logicalVolIntegrityDescImpUse *)
|
||||||
|
(((uint8_t *)(lvid + 1)) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UDF filesystem type */
|
/* UDF filesystem type */
|
||||||
|
@ -1548,6 +1542,7 @@ 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;
|
||||||
|
@ -1574,15 +1569,27 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
|
||||||
|
|
||||||
lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
|
lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
|
||||||
if (lvid->nextIntegrityExt.extLength == 0)
|
if (lvid->nextIntegrityExt.extLength == 0)
|
||||||
return;
|
goto check;
|
||||||
|
|
||||||
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