Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull mqueuefs revert from Eric Biederman:
 "This fixes a regression that came in the merge window for v4.16.

  The problem is that the permissions for mounting and using the
  mqueuefs filesystem are broken. The necessary permission check is
  missing letting people who should not be able to mount mqueuefs mount
  mqueuefs. The field sb->s_user_ns is set incorrectly not allowing the
  mounter of mqueuefs to remount and otherwise have proper control over
  the filesystem.

  Al Viro and I see the path to the necessary fixes differently and I am
  not even certain at this point he actually sees all of the necessary
  fixes. Given a couple weeks we can probably work something out but I
  don't see the review being resolved in time for the final v4.16. I
  don't want v4.16 shipping with a nasty regression. So unfortunately I
  am sending a revert"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  Revert "mqueue: switch to on-demand creation of internal mount"
This commit is contained in:
Linus Torvalds 2018-03-24 23:29:15 -07:00
commit e43d40b321

View File

@ -325,9 +325,8 @@ err:
static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct ipc_namespace *ns = data;
struct ipc_namespace *ns = sb->s_fs_info;
sb->s_fs_info = ns;
sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
@ -344,44 +343,18 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
static struct file_system_type mqueue_fs_type;
/*
* Return value is pinned only by reference in ->mq_mnt; it will
* live until ipcns dies. Caller does not need to drop it.
*/
static struct vfsmount *mq_internal_mount(void)
{
struct ipc_namespace *ns = current->nsproxy->ipc_ns;
struct vfsmount *m = ns->mq_mnt;
if (m)
return m;
m = kern_mount_data(&mqueue_fs_type, ns);
spin_lock(&mq_lock);
if (unlikely(ns->mq_mnt)) {
spin_unlock(&mq_lock);
if (!IS_ERR(m))
kern_unmount(m);
return ns->mq_mnt;
}
if (!IS_ERR(m))
ns->mq_mnt = m;
spin_unlock(&mq_lock);
return m;
}
static struct dentry *mqueue_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
{
struct vfsmount *m;
if (flags & SB_KERNMOUNT)
return mount_nodev(fs_type, flags, data, mqueue_fill_super);
m = mq_internal_mount();
if (IS_ERR(m))
return ERR_CAST(m);
atomic_inc(&m->mnt_sb->s_active);
down_write(&m->mnt_sb->s_umount);
return dget(m->mnt_root);
struct ipc_namespace *ns;
if (flags & SB_KERNMOUNT) {
ns = data;
data = NULL;
} else {
ns = current->nsproxy->ipc_ns;
}
return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
}
static void init_once(void *foo)
@ -771,16 +744,13 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro,
static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
struct mq_attr *attr)
{
struct vfsmount *mnt = mq_internal_mount();
struct dentry *root;
struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
struct dentry *root = mnt->mnt_root;
struct filename *name;
struct path path;
int fd, error;
int ro;
if (IS_ERR(mnt))
return PTR_ERR(mnt);
audit_mq_open(oflag, mode, attr);
if (IS_ERR(name = getname(u_name)))
@ -791,7 +761,6 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
goto out_putname;
ro = mnt_want_write(mnt); /* we'll drop it in any case */
root = mnt->mnt_root;
inode_lock(d_inode(root));
path.dentry = lookup_one_len(name->name, root, strlen(name->name));
if (IS_ERR(path.dentry)) {
@ -840,9 +809,6 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
struct vfsmount *mnt = ipc_ns->mq_mnt;
if (!mnt)
return -ENOENT;
name = getname(u_name);
if (IS_ERR(name))
return PTR_ERR(name);
@ -1569,26 +1535,28 @@ int mq_init_ns(struct ipc_namespace *ns)
ns->mq_msgsize_max = DFLT_MSGSIZEMAX;
ns->mq_msg_default = DFLT_MSG;
ns->mq_msgsize_default = DFLT_MSGSIZE;
ns->mq_mnt = NULL;
ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
if (IS_ERR(ns->mq_mnt)) {
int err = PTR_ERR(ns->mq_mnt);
ns->mq_mnt = NULL;
return err;
}
return 0;
}
void mq_clear_sbinfo(struct ipc_namespace *ns)
{
if (ns->mq_mnt)
ns->mq_mnt->mnt_sb->s_fs_info = NULL;
ns->mq_mnt->mnt_sb->s_fs_info = NULL;
}
void mq_put_mnt(struct ipc_namespace *ns)
{
if (ns->mq_mnt)
kern_unmount(ns->mq_mnt);
kern_unmount(ns->mq_mnt);
}
static int __init init_mqueue_fs(void)
{
struct vfsmount *m;
int error;
mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
@ -1610,10 +1578,6 @@ static int __init init_mqueue_fs(void)
if (error)
goto out_filesystem;
m = kern_mount_data(&mqueue_fs_type, &init_ipc_ns);
if (IS_ERR(m))
goto out_filesystem;
init_ipc_ns.mq_mnt = m;
return 0;
out_filesystem: