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

Commit 94bc891b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  [PATCH] get rid of __exit_files(), __exit_fs() and __put_fs_struct()
  [PATCH] proc_readfd_common() race fix
  [PATCH] double-free of inode on alloc_file() failure exit in create_write_pipe()
  [PATCH] teach seq_file to discard entries
  [PATCH] umount_tree() will unhash everything itself
  [PATCH] get rid of more nameidata passing in namespace.c
  [PATCH] switch a bunch of LSM hooks from nameidata to path
  [PATCH] lock exclusively in collect_mounts() and drop_collected_mounts()
  [PATCH] move a bunch of declarations to fs/internal.h
parents 934b7024 1ec7f1dd
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -43,3 +43,14 @@ extern void __init chrdev_init(void);
 * namespace.c
 * namespace.c
 */
 */
extern int copy_mount_options(const void __user *, unsigned long *);
extern int copy_mount_options(const void __user *, unsigned long *);

extern void free_vfsmnt(struct vfsmount *);
extern struct vfsmount *alloc_vfsmnt(const char *);
extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
				struct vfsmount *);
extern void release_mounts(struct list_head *);
extern void umount_tree(struct vfsmount *, int, struct list_head *);
extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);

extern void __init mnt_init(void);
+32 −34
Original line number Original line Diff line number Diff line
@@ -1091,20 +1091,20 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry)
struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry)
{
{
	struct vfsmount *tree;
	struct vfsmount *tree;
	down_read(&namespace_sem);
	down_write(&namespace_sem);
	tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE);
	tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE);
	up_read(&namespace_sem);
	up_write(&namespace_sem);
	return tree;
	return tree;
}
}


void drop_collected_mounts(struct vfsmount *mnt)
void drop_collected_mounts(struct vfsmount *mnt)
{
{
	LIST_HEAD(umount_list);
	LIST_HEAD(umount_list);
	down_read(&namespace_sem);
	down_write(&namespace_sem);
	spin_lock(&vfsmount_lock);
	spin_lock(&vfsmount_lock);
	umount_tree(mnt, 0, &umount_list);
	umount_tree(mnt, 0, &umount_list);
	spin_unlock(&vfsmount_lock);
	spin_unlock(&vfsmount_lock);
	up_read(&namespace_sem);
	up_write(&namespace_sem);
	release_mounts(&umount_list);
	release_mounts(&umount_list);
}
}


@@ -1205,32 +1205,32 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
	return 0;
	return 0;
}
}


static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
static int graft_tree(struct vfsmount *mnt, struct path *path)
{
{
	int err;
	int err;
	if (mnt->mnt_sb->s_flags & MS_NOUSER)
	if (mnt->mnt_sb->s_flags & MS_NOUSER)
		return -EINVAL;
		return -EINVAL;


	if (S_ISDIR(nd->path.dentry->d_inode->i_mode) !=
	if (S_ISDIR(path->dentry->d_inode->i_mode) !=
	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))
	      S_ISDIR(mnt->mnt_root->d_inode->i_mode))
		return -ENOTDIR;
		return -ENOTDIR;


	err = -ENOENT;
	err = -ENOENT;
	mutex_lock(&nd->path.dentry->d_inode->i_mutex);
	mutex_lock(&path->dentry->d_inode->i_mutex);
	if (IS_DEADDIR(nd->path.dentry->d_inode))
	if (IS_DEADDIR(path->dentry->d_inode))
		goto out_unlock;
		goto out_unlock;


	err = security_sb_check_sb(mnt, nd);
	err = security_sb_check_sb(mnt, path);
	if (err)
	if (err)
		goto out_unlock;
		goto out_unlock;


	err = -ENOENT;
	err = -ENOENT;
	if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry))
	if (IS_ROOT(path->dentry) || !d_unhashed(path->dentry))
		err = attach_recursive_mnt(mnt, &nd->path, NULL);
		err = attach_recursive_mnt(mnt, path, NULL);
out_unlock:
out_unlock:
	mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
	mutex_unlock(&path->dentry->d_inode->i_mutex);
	if (!err)
	if (!err)
		security_sb_post_addmount(mnt, nd);
		security_sb_post_addmount(mnt, path);
	return err;
	return err;
}
}


@@ -1294,7 +1294,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name,
	if (!mnt)
	if (!mnt)
		goto out;
		goto out;


	err = graft_tree(mnt, nd);
	err = graft_tree(mnt, &nd->path);
	if (err) {
	if (err) {
		LIST_HEAD(umount_list);
		LIST_HEAD(umount_list);
		spin_lock(&vfsmount_lock);
		spin_lock(&vfsmount_lock);
@@ -1501,7 +1501,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
		goto unlock;
		goto unlock;


	newmnt->mnt_flags = mnt_flags;
	newmnt->mnt_flags = mnt_flags;
	if ((err = graft_tree(newmnt, nd)))
	if ((err = graft_tree(newmnt, &nd->path)))
		goto unlock;
		goto unlock;


	if (fslist) /* add to the specified expiration list */
	if (fslist) /* add to the specified expiration list */
@@ -1746,7 +1746,8 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
	if (retval)
	if (retval)
		return retval;
		return retval;


	retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page);
	retval = security_sb_mount(dev_name, &nd.path,
				   type_page, flags, data_page);
	if (retval)
	if (retval)
		goto dput_out;
		goto dput_out;


@@ -1986,15 +1987,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
			       const char __user * put_old)
			       const char __user * put_old)
{
{
	struct vfsmount *tmp;
	struct vfsmount *tmp;
	struct nameidata new_nd, old_nd, user_nd;
	struct nameidata new_nd, old_nd;
	struct path parent_path, root_parent;
	struct path parent_path, root_parent, root;
	int error;
	int error;


	if (!capable(CAP_SYS_ADMIN))
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
		return -EPERM;


	lock_kernel();

	error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
	error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
			    &new_nd);
			    &new_nd);
	if (error)
	if (error)
@@ -2007,14 +2006,14 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
	if (error)
	if (error)
		goto out1;
		goto out1;


	error = security_sb_pivotroot(&old_nd, &new_nd);
	error = security_sb_pivotroot(&old_nd.path, &new_nd.path);
	if (error) {
	if (error) {
		path_put(&old_nd.path);
		path_put(&old_nd.path);
		goto out1;
		goto out1;
	}
	}


	read_lock(&current->fs->lock);
	read_lock(&current->fs->lock);
	user_nd.path = current->fs->root;
	root = current->fs->root;
	path_get(&current->fs->root);
	path_get(&current->fs->root);
	read_unlock(&current->fs->lock);
	read_unlock(&current->fs->lock);
	down_write(&namespace_sem);
	down_write(&namespace_sem);
@@ -2022,9 +2021,9 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
	error = -EINVAL;
	error = -EINVAL;
	if (IS_MNT_SHARED(old_nd.path.mnt) ||
	if (IS_MNT_SHARED(old_nd.path.mnt) ||
		IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) ||
		IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) ||
		IS_MNT_SHARED(user_nd.path.mnt->mnt_parent))
		IS_MNT_SHARED(root.mnt->mnt_parent))
		goto out2;
		goto out2;
	if (!check_mnt(user_nd.path.mnt))
	if (!check_mnt(root.mnt))
		goto out2;
		goto out2;
	error = -ENOENT;
	error = -ENOENT;
	if (IS_DEADDIR(new_nd.path.dentry->d_inode))
	if (IS_DEADDIR(new_nd.path.dentry->d_inode))
@@ -2034,13 +2033,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
	if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry))
	if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry))
		goto out2;
		goto out2;
	error = -EBUSY;
	error = -EBUSY;
	if (new_nd.path.mnt == user_nd.path.mnt ||
	if (new_nd.path.mnt == root.mnt ||
	    old_nd.path.mnt == user_nd.path.mnt)
	    old_nd.path.mnt == root.mnt)
		goto out2; /* loop, on the same file system  */
		goto out2; /* loop, on the same file system  */
	error = -EINVAL;
	error = -EINVAL;
	if (user_nd.path.mnt->mnt_root != user_nd.path.dentry)
	if (root.mnt->mnt_root != root.dentry)
		goto out2; /* not a mountpoint */
		goto out2; /* not a mountpoint */
	if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt)
	if (root.mnt->mnt_parent == root.mnt)
		goto out2; /* not attached */
		goto out2; /* not attached */
	if (new_nd.path.mnt->mnt_root != new_nd.path.dentry)
	if (new_nd.path.mnt->mnt_root != new_nd.path.dentry)
		goto out2; /* not a mountpoint */
		goto out2; /* not a mountpoint */
@@ -2062,27 +2061,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
	} else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry))
	} else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry))
		goto out3;
		goto out3;
	detach_mnt(new_nd.path.mnt, &parent_path);
	detach_mnt(new_nd.path.mnt, &parent_path);
	detach_mnt(user_nd.path.mnt, &root_parent);
	detach_mnt(root.mnt, &root_parent);
	/* mount old root on put_old */
	/* mount old root on put_old */
	attach_mnt(user_nd.path.mnt, &old_nd.path);
	attach_mnt(root.mnt, &old_nd.path);
	/* mount new_root on / */
	/* mount new_root on / */
	attach_mnt(new_nd.path.mnt, &root_parent);
	attach_mnt(new_nd.path.mnt, &root_parent);
	touch_mnt_namespace(current->nsproxy->mnt_ns);
	touch_mnt_namespace(current->nsproxy->mnt_ns);
	spin_unlock(&vfsmount_lock);
	spin_unlock(&vfsmount_lock);
	chroot_fs_refs(&user_nd.path, &new_nd.path);
	chroot_fs_refs(&root, &new_nd.path);
	security_sb_post_pivotroot(&user_nd, &new_nd);
	security_sb_post_pivotroot(&root, &new_nd.path);
	error = 0;
	error = 0;
	path_put(&root_parent);
	path_put(&root_parent);
	path_put(&parent_path);
	path_put(&parent_path);
out2:
out2:
	mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex);
	mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex);
	up_write(&namespace_sem);
	up_write(&namespace_sem);
	path_put(&user_nd.path);
	path_put(&root);
	path_put(&old_nd.path);
	path_put(&old_nd.path);
out1:
out1:
	path_put(&new_nd.path);
	path_put(&new_nd.path);
out0:
out0:
	unlock_kernel();
	return error;
	return error;
out3:
out3:
	spin_unlock(&vfsmount_lock);
	spin_unlock(&vfsmount_lock);
+3 −0
Original line number Original line Diff line number Diff line
@@ -988,7 +988,10 @@ struct file *create_write_pipe(void)
	return f;
	return f;


 err_dentry:
 err_dentry:
	free_pipe_info(inode);
	dput(dentry);
	dput(dentry);
	return ERR_PTR(err);

 err_inode:
 err_inode:
	free_pipe_info(inode);
	free_pipe_info(inode);
	iput(inode);
	iput(inode);
+2 −2
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/mnt_namespace.h>
#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/mount.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include "internal.h"
#include "pnode.h"
#include "pnode.h"


/* return the next shared peer mount of @p */
/* return the next shared peer mount of @p */
@@ -211,8 +212,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry,
out:
out:
	spin_lock(&vfsmount_lock);
	spin_lock(&vfsmount_lock);
	while (!list_empty(&tmp_list)) {
	while (!list_empty(&tmp_list)) {
		child = list_entry(tmp_list.next, struct vfsmount, mnt_hash);
		child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash);
		list_del_init(&child->mnt_hash);
		umount_tree(child, 0, &umount_list);
		umount_tree(child, 0, &umount_list);
	}
	}
	spin_unlock(&vfsmount_lock);
	spin_unlock(&vfsmount_lock);
+1 −0
Original line number Original line Diff line number Diff line
@@ -35,4 +35,5 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *,
		struct list_head *);
		struct list_head *);
int propagate_umount(struct list_head *);
int propagate_umount(struct list_head *);
int propagate_mount_busy(struct vfsmount *, int);
int propagate_mount_busy(struct vfsmount *, int);
void mnt_release_group_id(struct vfsmount *);
#endif /* _LINUX_PNODE_H */
#endif /* _LINUX_PNODE_H */
Loading