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

Commit 2a32cebd authored by Al Viro's avatar Al Viro
Browse files

Fix races around the access to ->s_options



Put generic_show_options read access to s_options under rcu_read_lock,
split save_mount_options() into "we are setting it the first time"
(uses in foo_fill_super()) and "we are relacing and freeing the old one",
synchronize_rcu() before kfree() in the latter.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent f9dbd05b
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -75,8 +75,7 @@ static int capifs_remount(struct super_block *s, int *flags, char *data)
		}
	}

	kfree(s->s_options);
	s->s_options = new_opt;
	replace_mount_options(s, new_opt);

	config.setuid  = setuid;
	config.setgid  = setgid;
+1 −2
Original line number Diff line number Diff line
@@ -507,8 +507,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
		kfree(new_opts);
		return -EINVAL;
	}
	kfree(sb->s_options);
	sb->s_options = new_opts;
	replace_mount_options(sb, new_opts);

	sbi->s_flags = mount_flags;
	sbi->s_mode  = mode;
+2 −2
Original line number Diff line number Diff line
@@ -408,17 +408,17 @@ static int afs_get_sb(struct file_system_type *fs_type,
			deactivate_locked_super(sb);
			goto error;
		}
		sb->s_options = new_opts;
		save_mount_options(sb, new_opts);
		sb->s_flags |= MS_ACTIVE;
	} else {
		_debug("reuse");
		kfree(new_opts);
		ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
	}

	simple_set_mnt(mnt, sb);
	afs_put_volume(params.volume);
	afs_put_cell(params.cell);
	kfree(new_opts);
	_leave(" = 0 [%p]", sb);
	return 0;

+1 −2
Original line number Diff line number Diff line
@@ -423,8 +423,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)

	if (!(*flags & MS_RDONLY)) mark_dirty(s);

	kfree(s->s_options);
	s->s_options = new_opts;
	replace_mount_options(s, new_opts);

	return 0;

+18 −3
Original line number Diff line number Diff line
@@ -695,12 +695,16 @@ static inline void mangle(struct seq_file *m, const char *s)
 */
int generic_show_options(struct seq_file *m, struct vfsmount *mnt)
{
	const char *options = mnt->mnt_sb->s_options;
	const char *options;

	rcu_read_lock();
	options = rcu_dereference(mnt->mnt_sb->s_options);

	if (options != NULL && options[0]) {
		seq_putc(m, ',');
		mangle(m, options);
	}
	rcu_read_unlock();

	return 0;
}
@@ -721,11 +725,22 @@ EXPORT_SYMBOL(generic_show_options);
 */
void save_mount_options(struct super_block *sb, char *options)
{
	kfree(sb->s_options);
	sb->s_options = kstrdup(options, GFP_KERNEL);
	BUG_ON(sb->s_options);
	rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
}
EXPORT_SYMBOL(save_mount_options);

void replace_mount_options(struct super_block *sb, char *options)
{
	char *old = sb->s_options;
	rcu_assign_pointer(sb->s_options, options);
	if (old) {
		synchronize_rcu();
		kfree(old);
	}
}
EXPORT_SYMBOL(replace_mount_options);

#ifdef CONFIG_PROC_FS
/* iterator */
static void *m_start(struct seq_file *m, loff_t *pos)
Loading