Skip to content

Commit

Permalink
udf: Check LVID earlier
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jankara committed Aug 11, 2021
1 parent 902e7f3 commit 781d2a9
Showing 1 changed file with 16 additions and 9 deletions.
25 changes: 16 additions & 9 deletions fs/udf/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -1542,6 +1536,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;
Expand All @@ -1568,15 +1563,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;
}
}

/*
Expand Down

0 comments on commit 781d2a9

Please sign in to comment.