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

Commit 8035d1a1 authored by Jan Kara's avatar Jan Kara Committed by Greg Kroah-Hartman
Browse files

udf: Prevent write-unsupported filesystem to be remounted read-write



[ Upstream commit a9ad01bc759df79b0012f43ee52164391e31cd96 ]

There are certain filesystem features which we support for reading but
not for writing. We properly refuse to mount such filesystems read-write
however for some features (such as read-only partitions), we don't check
for these features when remounting the filesystem from read-only to
read-write. Thus such filesystems could be remounted read-write leading
to strange behavior (most likely crashes).

Fix the problem by marking in superblock whether the filesystem has some
features that are supported in read-only mode and check this flag during
remount.

Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 949fd0ea
Loading
Loading
Loading
Loading
+16 −14
Original line number Original line Diff line number Diff line
@@ -613,14 +613,11 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
	struct udf_options uopt;
	struct udf_options uopt;
	struct udf_sb_info *sbi = UDF_SB(sb);
	struct udf_sb_info *sbi = UDF_SB(sb);
	int error = 0;
	int error = 0;
	struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);


	sync_filesystem(sb);
	if (!(*flags & SB_RDONLY) && UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT))
	if (lvidiu) {
		int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);
		if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & SB_RDONLY))
		return -EACCES;
		return -EACCES;
	}

	sync_filesystem(sb);


	uopt.flags = sbi->s_flags;
	uopt.flags = sbi->s_flags;
	uopt.uid   = sbi->s_uid;
	uopt.uid   = sbi->s_uid;
@@ -1257,6 +1254,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
			ret = -EACCES;
			ret = -EACCES;
			goto out_bh;
			goto out_bh;
		}
		}
		UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
		ret = udf_load_vat(sb, i, type1_idx);
		ret = udf_load_vat(sb, i, type1_idx);
		if (ret < 0)
		if (ret < 0)
			goto out_bh;
			goto out_bh;
@@ -2155,11 +2153,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
				UDF_MAX_READ_VERSION);
				UDF_MAX_READ_VERSION);
			ret = -EINVAL;
			ret = -EINVAL;
			goto error_out;
			goto error_out;
		} else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION &&
		} else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) {
			   !sb_rdonly(sb)) {
			if (!sb_rdonly(sb)) {
				ret = -EACCES;
				ret = -EACCES;
				goto error_out;
				goto error_out;
			}
			}
			UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
		}


		sbi->s_udfrev = minUDFWriteRev;
		sbi->s_udfrev = minUDFWriteRev;


@@ -2176,11 +2176,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
	}
	}


	if (sbi->s_partmaps[sbi->s_partition].s_partition_flags &
	if (sbi->s_partmaps[sbi->s_partition].s_partition_flags &
			UDF_PART_FLAG_READ_ONLY &&
			UDF_PART_FLAG_READ_ONLY) {
	    !sb_rdonly(sb)) {
		if (!sb_rdonly(sb)) {
			ret = -EACCES;
			ret = -EACCES;
			goto error_out;
			goto error_out;
		}
		}
		UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
	}


	if (udf_find_fileset(sb, &fileset, &rootdir)) {
	if (udf_find_fileset(sb, &fileset, &rootdir)) {
		udf_warn(sb, "No fileset found\n");
		udf_warn(sb, "No fileset found\n");
+2 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,8 @@
#define UDF_FLAG_LASTBLOCK_SET	16
#define UDF_FLAG_LASTBLOCK_SET	16
#define UDF_FLAG_BLOCKSIZE_SET	17
#define UDF_FLAG_BLOCKSIZE_SET	17
#define UDF_FLAG_INCONSISTENT	18
#define UDF_FLAG_INCONSISTENT	18
#define UDF_FLAG_RW_INCOMPAT	19	/* Set when we find RW incompatible
					 * feature */


#define UDF_PART_FLAG_UNALLOC_BITMAP	0x0001
#define UDF_PART_FLAG_UNALLOC_BITMAP	0x0001
#define UDF_PART_FLAG_UNALLOC_TABLE	0x0002
#define UDF_PART_FLAG_UNALLOC_TABLE	0x0002