| From 1db7e9aeb3a9983b251c4db18e0e4917e367ded7 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 3 May 2021 11:39:03 +0200 |
| Subject: udf: Check LVID earlier |
| |
| From: Jan Kara <jack@suse.cz> |
| |
| [ 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> |
| --- |
| fs/udf/super.c | 25 ++++++++++++++++--------- |
| 1 file changed, 16 insertions(+), 9 deletions(-) |
| |
| diff --git a/fs/udf/super.c b/fs/udf/super.c |
| index d0df217f4712..a59bf469dd1c 100644 |
| --- a/fs/udf/super.c |
| +++ b/fs/udf/super.c |
| @@ -108,16 +108,10 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb) |
| return NULL; |
| lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data; |
| 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 */ |
| offset = partnum * 2 * sizeof(uint32_t); |
| - return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]); |
| + return (struct logicalVolIntegrityDescImpUse *) |
| + (((uint8_t *)(lvid + 1)) + offset); |
| } |
| |
| /* UDF filesystem type */ |
| @@ -1541,6 +1535,7 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ |
| struct udf_sb_info *sbi = UDF_SB(sb); |
| struct logicalVolIntegrityDesc *lvid; |
| int indirections = 0; |
| + u32 parts, impuselen; |
| |
| while (++indirections <= UDF_MAX_LVID_NESTING) { |
| final_bh = NULL; |
| @@ -1567,15 +1562,27 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ |
| |
| lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data; |
| if (lvid->nextIntegrityExt.extLength == 0) |
| - return; |
| + goto check; |
| |
| loc = leea_to_cpu(lvid->nextIntegrityExt); |
| } |
| |
| udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n", |
| UDF_MAX_LVID_NESTING); |
| +out_err: |
| brelse(sbi->s_lvid_bh); |
| 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; |
| + } |
| } |
| |
| /* |
| -- |
| 2.30.2 |
| |