Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86987cf0 authored by Jan Kara's avatar Jan Kara Committed by Greg Kroah-Hartman
Browse files

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: default avatar <syzbot+7fbfe5fed73ebb675748@syzkaller.appspotmail.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent cc608af3
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -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 */
@@ -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 logicalVolIntegrityDesc *lvid;
	int indirections = 0;
	u32 parts, impuselen;

	while (++indirections <= UDF_MAX_LVID_NESTING) {
		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;
		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;
	}
}

/*