History

Revert "mqueue: switch to on-demand creation of internal mount"

This reverts commit 36735a6a2b5e042db1af956ce4bcc13f3ff99e21. Aleksa Sarai <asarai@suse.de> writes: > [REGRESSION v4.16-rc6] [PATCH] mqueue: forbid unprivileged user access to internal mount > > Felix reported weird behaviour on 4.16.0-rc6 with regards to mqueue[1], > which was introduced by 36735a6a2b5e ("mqueue: switch to on-demand > creation of internal mount"). > > Basically, the reproducer boils down to being able to mount mqueue if > you create a new user namespace, even if you don't unshare the IPC > namespace. > > Previously this was not possible, and you would get an -EPERM. The mount > is the *host* mqueue mount, which is being cached and just returned from > mqueue_mount(). To be honest, I'm not sure if this is safe or not (or if > it was intentional -- since I'm not familiar with mqueue). > > To me it looks like there is a missing permission check. I've included a > patch below that I've compile-tested, and should block the above case. > Can someone please tell me if I'm missing something? Is this actually > safe? > > [1]: https://github.com/docker/docker/issues/36674 The issue is a lot deeper than a missing permission check. sb->s_user_ns was is improperly set as well. So in addition to the filesystem being mounted when it should not be mounted, so things are not allow that should be. We are practically to the release of 4.16 and there is no agreement between Al Viro and myself on what the code should looks like to fix things properly. So revert the code to what it was before so that we can take our time and discuss this properly.

Eric W. Biederman committed 8 years ago

Commit cfb2f6f1 parent 91ab8831 file · +19 −55Browse files

Unified · Split

ipc/mqueue.c+19−55
@@ -325,9 +325,8 @@ err: · 324 unmodified lines
325325 static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
326326 {
327327 struct inode *inode;
328− struct ipc_namespace *ns = data;
328+ struct ipc_namespace *ns = sb->s_fs_info;
329329
330− sb->s_fs_info = ns;
331330 sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
332331 sb->s_blocksize = PAGE_SIZE;
333332 sb->s_blocksize_bits = PAGE_SHIFT;
@@ -344,44 +343,18 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) · 10 unmodified lines
344343 return 0;
345344 }
346345
347−static struct file_system_type mqueue_fs_type;
348−/*
349− * Return value is pinned only by reference in ->mq_mnt; it will
350− * live until ipcns dies. Caller does not need to drop it.
351− */
352−static struct vfsmount *mq_internal_mount(void)
353−{
354− struct ipc_namespace *ns = current->nsproxy->ipc_ns;
355− struct vfsmount *m = ns->mq_mnt;
356− if (m)
357− return m;
358− m = kern_mount_data(&mqueue_fs_type, ns);
359− spin_lock(&mq_lock);
360− if (unlikely(ns->mq_mnt)) {
361− spin_unlock(&mq_lock);
362− if (!IS_ERR(m))
363− kern_unmount(m);
364− return ns->mq_mnt;
365− }
366− if (!IS_ERR(m))
367− ns->mq_mnt = m;
368− spin_unlock(&mq_lock);
369− return m;
370−}
371−
372346 static struct dentry *mqueue_mount(struct file_system_type *fs_type,
373347 int flags, const char *dev_name,
374348 void *data)
375349 {
376− struct vfsmount *m;
377− if (flags & SB_KERNMOUNT)
378− return mount_nodev(fs_type, flags, data, mqueue_fill_super);
379− m = mq_internal_mount();
380− if (IS_ERR(m))
381− return ERR_CAST(m);
382− atomic_inc(&m->mnt_sb->s_active);
383− down_write(&m->mnt_sb->s_umount);
384− return dget(m->mnt_root);
350+ struct ipc_namespace *ns;
351+ if (flags & SB_KERNMOUNT) {
352+ ns = data;
353+ data = NULL;
354+ } else {
355+ ns = current->nsproxy->ipc_ns;
356+ }
357+ return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
385358 }
386359
387360 static void init_once(void *foo)
@@ -771,16 +744,13 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro, · 383 unmodified lines
771744 static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
772745 struct mq_attr *attr)
773746 {
774− struct vfsmount *mnt = mq_internal_mount();
775− struct dentry *root;
747+ struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
748+ struct dentry *root = mnt->mnt_root;
776749 struct filename *name;
777750 struct path path;
778751 int fd, error;
779752 int ro;
780753
781− if (IS_ERR(mnt))
782− return PTR_ERR(mnt);
783−
784754 audit_mq_open(oflag, mode, attr);
785755
786756 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, · 4 unmodified lines
791761 goto out_putname;
792762
793763 ro = mnt_want_write(mnt); /* we'll drop it in any case */
794− root = mnt->mnt_root;
795764 inode_lock(d_inode(root));
796765 path.dentry = lookup_one_len(name->name, root, strlen(name->name));
797766 if (IS_ERR(path.dentry)) {
@@ -840,9 +809,6 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) · 42 unmodified lines
840809 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
841810 struct vfsmount *mnt = ipc_ns->mq_mnt;
842811
843− if (!mnt)
844− return -ENOENT;
845−
846812 name = getname(u_name);
847813 if (IS_ERR(name))
848814 return PTR_ERR(name);
@@ -1569,26 +1535,28 @@ int mq_init_ns(struct ipc_namespace *ns) · 720 unmodified lines
15691535 ns->mq_msgsize_max = DFLT_MSGSIZEMAX;
15701536 ns->mq_msg_default = DFLT_MSG;
15711537 ns->mq_msgsize_default = DFLT_MSGSIZE;
1572− ns->mq_mnt = NULL;
15731538
1539+ ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
1540+ if (IS_ERR(ns->mq_mnt)) {
1541+ int err = PTR_ERR(ns->mq_mnt);
1542+ ns->mq_mnt = NULL;
1543+ return err;
1544+ }
15741545 return 0;
15751546 }
15761547
15771548 void mq_clear_sbinfo(struct ipc_namespace *ns)
15781549 {
1579− if (ns->mq_mnt)
1580− ns->mq_mnt->mnt_sb->s_fs_info = NULL;
1550+ ns->mq_mnt->mnt_sb->s_fs_info = NULL;
15811551 }
15821552
15831553 void mq_put_mnt(struct ipc_namespace *ns)
15841554 {
1585− if (ns->mq_mnt)
1586− kern_unmount(ns->mq_mnt);
1555+ kern_unmount(ns->mq_mnt);
15871556 }
15881557
15891558 static int __init init_mqueue_fs(void)
15901559 {
1591− struct vfsmount *m;
15921560 int error;
15931561
15941562 mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
@@ -1610,10 +1578,6 @@ static int __init init_mqueue_fs(void) · 15 unmodified lines
16101578 if (error)
16111579 goto out_filesystem;
16121580
1613− m = kern_mount_data(&mqueue_fs_type, &init_ipc_ns);
1614− if (IS_ERR(m))
1615− goto out_filesystem;
1616− init_ipc_ns.mq_mnt = m;
16171581 return 0;
16181582
16191583 out_filesystem:

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t