4094 lines · 98.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  linux/fs/namespace.c * * (C) Copyright Al Viro 2000, 2001 * * Based on code from fs/super.c, copyright Linus Torvalds and others. * Heavily rewritten. */ #include <linux/syscalls.h>#include <linux/export.h>#include <linux/capability.h>#include <linux/mnt_namespace.h>#include <linux/user_namespace.h>#include <linux/namei.h>#include <linux/security.h>#include <linux/cred.h>#include <linux/idr.h>#include <linux/init.h>		/* init_rootfs */#include <linux/fs_struct.h>	/* get_fs_root et.al. */#include <linux/fsnotify.h>	/* fsnotify_vfsmount_delete */#include <linux/file.h>#include <linux/uaccess.h>#include <linux/proc_ns.h>#include <linux/magic.h>#include <linux/memblock.h>#include <linux/task_work.h>#include <linux/sched/task.h>#include <uapi/linux/mount.h>#include <linux/fs_context.h>#include <linux/shmem_fs.h> #include "pnode.h"#include "internal.h" /* Maximum number of mounts in a mount namespace */unsigned int sysctl_mount_max __read_mostly = 100000; static unsigned int m_hash_mask __read_mostly;static unsigned int m_hash_shift __read_mostly;static unsigned int mp_hash_mask __read_mostly;static unsigned int mp_hash_shift __read_mostly; static __initdata unsigned long mhash_entries;static int __init set_mhash_entries(char *str){	if (!str)		return 0;	mhash_entries = simple_strtoul(str, &str, 0);	return 1;}__setup("mhash_entries=", set_mhash_entries); static __initdata unsigned long mphash_entries;static int __init set_mphash_entries(char *str){	if (!str)		return 0;	mphash_entries = simple_strtoul(str, &str, 0);	return 1;}__setup("mphash_entries=", set_mphash_entries); static u64 event;static DEFINE_IDA(mnt_id_ida);static DEFINE_IDA(mnt_group_ida); static struct hlist_head *mount_hashtable __read_mostly;static struct hlist_head *mountpoint_hashtable __read_mostly;static struct kmem_cache *mnt_cache __read_mostly;static DECLARE_RWSEM(namespace_sem);static HLIST_HEAD(unmounted);	/* protected by namespace_sem */static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */ /* /sys/fs */struct kobject *fs_kobj;EXPORT_SYMBOL_GPL(fs_kobj); /* * vfsmount lock may be taken for read to prevent changes to the * vfsmount hash, ie. during mountpoint lookups or walking back * up the tree. * * It should be taken for write in all cases where the vfsmount * tree or hash is modified or when a vfsmount structure is modified. */__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock); static inline struct hlist_head *m_hash(struct vfsmount *mnt, struct dentry *dentry){	unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);	tmp += ((unsigned long)dentry / L1_CACHE_BYTES);	tmp = tmp + (tmp >> m_hash_shift);	return &mount_hashtable[tmp & m_hash_mask];} static inline struct hlist_head *mp_hash(struct dentry *dentry){	unsigned long tmp = ((unsigned long)dentry / L1_CACHE_BYTES);	tmp = tmp + (tmp >> mp_hash_shift);	return &mountpoint_hashtable[tmp & mp_hash_mask];} static int mnt_alloc_id(struct mount *mnt){	int res = ida_alloc(&mnt_id_ida, GFP_KERNEL); 	if (res < 0)		return res;	mnt->mnt_id = res;	return 0;} static void mnt_free_id(struct mount *mnt){	ida_free(&mnt_id_ida, mnt->mnt_id);} /* * Allocate a new peer group ID */static int mnt_alloc_group_id(struct mount *mnt){	int res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL); 	if (res < 0)		return res;	mnt->mnt_group_id = res;	return 0;} /* * Release a peer group ID */void mnt_release_group_id(struct mount *mnt){	ida_free(&mnt_group_ida, mnt->mnt_group_id);	mnt->mnt_group_id = 0;} /* * vfsmount lock must be held for read */static inline void mnt_add_count(struct mount *mnt, int n){#ifdef CONFIG_SMP	this_cpu_add(mnt->mnt_pcp->mnt_count, n);#else	preempt_disable();	mnt->mnt_count += n;	preempt_enable();#endif} /* * vfsmount lock must be held for write */unsigned int mnt_get_count(struct mount *mnt){#ifdef CONFIG_SMP	unsigned int count = 0;	int cpu; 	for_each_possible_cpu(cpu) {		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;	} 	return count;#else	return mnt->mnt_count;#endif} static struct mount *alloc_vfsmnt(const char *name){	struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);	if (mnt) {		int err; 		err = mnt_alloc_id(mnt);		if (err)			goto out_free_cache; 		if (name) {			mnt->mnt_devname = kstrdup_const(name, GFP_KERNEL);			if (!mnt->mnt_devname)				goto out_free_id;		} #ifdef CONFIG_SMP		mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);		if (!mnt->mnt_pcp)			goto out_free_devname; 		this_cpu_add(mnt->mnt_pcp->mnt_count, 1);#else		mnt->mnt_count = 1;		mnt->mnt_writers = 0;#endif 		INIT_HLIST_NODE(&mnt->mnt_hash);		INIT_LIST_HEAD(&mnt->mnt_child);		INIT_LIST_HEAD(&mnt->mnt_mounts);		INIT_LIST_HEAD(&mnt->mnt_list);		INIT_LIST_HEAD(&mnt->mnt_expire);		INIT_LIST_HEAD(&mnt->mnt_share);		INIT_LIST_HEAD(&mnt->mnt_slave_list);		INIT_LIST_HEAD(&mnt->mnt_slave);		INIT_HLIST_NODE(&mnt->mnt_mp_list);		INIT_LIST_HEAD(&mnt->mnt_umounting);		INIT_HLIST_HEAD(&mnt->mnt_stuck_children);	}	return mnt; #ifdef CONFIG_SMPout_free_devname:	kfree_const(mnt->mnt_devname);#endifout_free_id:	mnt_free_id(mnt);out_free_cache:	kmem_cache_free(mnt_cache, mnt);	return NULL;} /* * Most r/o checks on a fs are for operations that take * discrete amounts of time, like a write() or unlink(). * We must keep track of when those operations start * (for permission checks) and when they end, so that * we can determine when writes are able to occur to * a filesystem. *//* * __mnt_is_readonly: check whether a mount is read-only * @mnt: the mount to check for its write status * * This shouldn't be used directly ouside of the VFS. * It does not guarantee that the filesystem will stay * r/w, just that it is right *now*.  This can not and * should not be used in place of IS_RDONLY(inode). * mnt_want/drop_write() will _keep_ the filesystem * r/w. */bool __mnt_is_readonly(struct vfsmount *mnt){	return (mnt->mnt_flags & MNT_READONLY) || sb_rdonly(mnt->mnt_sb);}EXPORT_SYMBOL_GPL(__mnt_is_readonly); static inline void mnt_inc_writers(struct mount *mnt){#ifdef CONFIG_SMP	this_cpu_inc(mnt->mnt_pcp->mnt_writers);#else	mnt->mnt_writers++;#endif} static inline void mnt_dec_writers(struct mount *mnt){#ifdef CONFIG_SMP	this_cpu_dec(mnt->mnt_pcp->mnt_writers);#else	mnt->mnt_writers--;#endif} static unsigned int mnt_get_writers(struct mount *mnt){#ifdef CONFIG_SMP	unsigned int count = 0;	int cpu; 	for_each_possible_cpu(cpu) {		count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers;	} 	return count;#else	return mnt->mnt_writers;#endif} static int mnt_is_readonly(struct vfsmount *mnt){	if (mnt->mnt_sb->s_readonly_remount)		return 1;	/* Order wrt setting s_flags/s_readonly_remount in do_remount() */	smp_rmb();	return __mnt_is_readonly(mnt);} /* * Most r/o & frozen checks on a fs are for operations that take discrete * amounts of time, like a write() or unlink().  We must keep track of when * those operations start (for permission checks) and when they end, so that we * can determine when writes are able to occur to a filesystem. *//** * __mnt_want_write - get write access to a mount without freeze protection * @m: the mount on which to take a write * * This tells the low-level filesystem that a write is about to be performed to * it, and makes sure that writes are allowed (mnt it read-write) before * returning success. This operation does not protect against filesystem being * frozen. When the write operation is finished, __mnt_drop_write() must be * called. This is effectively a refcount. */int __mnt_want_write(struct vfsmount *m){	struct mount *mnt = real_mount(m);	int ret = 0; 	preempt_disable();	mnt_inc_writers(mnt);	/*	 * The store to mnt_inc_writers must be visible before we pass	 * MNT_WRITE_HOLD loop below, so that the slowpath can see our	 * incremented count after it has set MNT_WRITE_HOLD.	 */	smp_mb();	while (READ_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD)		cpu_relax();	/*	 * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will	 * be set to match its requirements. So we must not load that until	 * MNT_WRITE_HOLD is cleared.	 */	smp_rmb();	if (mnt_is_readonly(m)) {		mnt_dec_writers(mnt);		ret = -EROFS;	}	preempt_enable(); 	return ret;} /** * mnt_want_write - get write access to a mount * @m: the mount on which to take a write * * This tells the low-level filesystem that a write is about to be performed to * it, and makes sure that writes are allowed (mount is read-write, filesystem * is not frozen) before returning success.  When the write operation is * finished, mnt_drop_write() must be called.  This is effectively a refcount. */int mnt_want_write(struct vfsmount *m){	int ret; 	sb_start_write(m->mnt_sb);	ret = __mnt_want_write(m);	if (ret)		sb_end_write(m->mnt_sb);	return ret;}EXPORT_SYMBOL_GPL(mnt_want_write); /** * mnt_clone_write - get write access to a mount * @mnt: the mount on which to take a write * * This is effectively like mnt_want_write, except * it must only be used to take an extra write reference * on a mountpoint that we already know has a write reference * on it. This allows some optimisation. * * After finished, mnt_drop_write must be called as usual to * drop the reference. */int mnt_clone_write(struct vfsmount *mnt){	/* superblock may be r/o */	if (__mnt_is_readonly(mnt))		return -EROFS;	preempt_disable();	mnt_inc_writers(real_mount(mnt));	preempt_enable();	return 0;}EXPORT_SYMBOL_GPL(mnt_clone_write); /** * __mnt_want_write_file - get write access to a file's mount * @file: the file who's mount on which to take a write * * This is like __mnt_want_write, but it takes a file and can * do some optimisations if the file is open for write already */int __mnt_want_write_file(struct file *file){	if (!(file->f_mode & FMODE_WRITER))		return __mnt_want_write(file->f_path.mnt);	else		return mnt_clone_write(file->f_path.mnt);} /** * mnt_want_write_file - get write access to a file's mount * @file: the file who's mount on which to take a write * * This is like mnt_want_write, but it takes a file and can * do some optimisations if the file is open for write already */int mnt_want_write_file(struct file *file){	int ret; 	sb_start_write(file_inode(file)->i_sb);	ret = __mnt_want_write_file(file);	if (ret)		sb_end_write(file_inode(file)->i_sb);	return ret;}EXPORT_SYMBOL_GPL(mnt_want_write_file); /** * __mnt_drop_write - give up write access to a mount * @mnt: the mount on which to give up write access * * Tells the low-level filesystem that we are done * performing writes to it.  Must be matched with * __mnt_want_write() call above. */void __mnt_drop_write(struct vfsmount *mnt){	preempt_disable();	mnt_dec_writers(real_mount(mnt));	preempt_enable();} /** * mnt_drop_write - give up write access to a mount * @mnt: the mount on which to give up write access * * Tells the low-level filesystem that we are done performing writes to it and * also allows filesystem to be frozen again.  Must be matched with * mnt_want_write() call above. */void mnt_drop_write(struct vfsmount *mnt){	__mnt_drop_write(mnt);	sb_end_write(mnt->mnt_sb);}EXPORT_SYMBOL_GPL(mnt_drop_write); void __mnt_drop_write_file(struct file *file){	__mnt_drop_write(file->f_path.mnt);} void mnt_drop_write_file(struct file *file){	__mnt_drop_write_file(file);	sb_end_write(file_inode(file)->i_sb);}EXPORT_SYMBOL(mnt_drop_write_file); static int mnt_make_readonly(struct mount *mnt){	int ret = 0; 	lock_mount_hash();	mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;	/*	 * After storing MNT_WRITE_HOLD, we'll read the counters. This store	 * should be visible before we do.	 */	smp_mb(); 	/*	 * With writers on hold, if this value is zero, then there are	 * definitely no active writers (although held writers may subsequently	 * increment the count, they'll have to wait, and decrement it after	 * seeing MNT_READONLY).	 *	 * It is OK to have counter incremented on one CPU and decremented on	 * another: the sum will add up correctly. The danger would be when we	 * sum up each counter, if we read a counter before it is incremented,	 * but then read another CPU's count which it has been subsequently	 * decremented from -- we would see more decrements than we should.	 * MNT_WRITE_HOLD protects against this scenario, because	 * mnt_want_write first increments count, then smp_mb, then spins on	 * MNT_WRITE_HOLD, so it can't be decremented by another CPU while	 * we're counting up here.	 */	if (mnt_get_writers(mnt) > 0)		ret = -EBUSY;	else		mnt->mnt.mnt_flags |= MNT_READONLY;	/*	 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers	 * that become unheld will see MNT_READONLY.	 */	smp_wmb();	mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;	unlock_mount_hash();

Lines 1–500 of 4094.