summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2018-03-24 12:28:14 -0400
committerEric W. Biederman <ebiederm@xmission.com>2018-03-24 20:34:23 -0400
commitcfb2f6f6e0ba11ea7b263d6b69c170c4b32ac0ea (patch)
tree1836d4f17e9e7a99f49e9810ff14f0b65389b572 /ipc
parent91ab883eb21325ad80f3473633f794c78ac87f51 (diff)
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. Fixes: 36735a6a2b5e ("mqueue: switch to on-demand creation of internal mount") Reported-by: Felix Abecassis <fabecassis@nvidia.com> Reported-by: Aleksa Sarai <asarai@suse.de> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/mqueue.c74
1 files changed, 19 insertions, 55 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index d7f309f74dec..a808f29d4c5a 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -325,9 +325,8 @@ err:
325static int mqueue_fill_super(struct super_block *sb, void *data, int silent) 325static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
326{ 326{
327 struct inode *inode; 327 struct inode *inode;
328 struct ipc_namespace *ns = data; 328 struct ipc_namespace *ns = sb->s_fs_info;
329 329
330 sb->s_fs_info = ns;
331 sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; 330 sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
332 sb->s_blocksize = PAGE_SIZE; 331 sb->s_blocksize = PAGE_SIZE;
333 sb->s_blocksize_bits = PAGE_SHIFT; 332 sb->s_blocksize_bits = PAGE_SHIFT;
@@ -344,44 +343,18 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
344 return 0; 343 return 0;
345} 344}
346 345
347static 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 */
352static 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
372static struct dentry *mqueue_mount(struct file_system_type *fs_type, 346static struct dentry *mqueue_mount(struct file_system_type *fs_type,
373 int flags, const char *dev_name, 347 int flags, const char *dev_name,
374 void *data) 348 void *data)
375{ 349{
376 struct vfsmount *m; 350 struct ipc_namespace *ns;
377 if (flags & SB_KERNMOUNT) 351 if (flags & SB_KERNMOUNT) {
378 return mount_nodev(fs_type, flags, data, mqueue_fill_super); 352 ns = data;
379 m = mq_internal_mount(); 353 data = NULL;
380 if (IS_ERR(m)) 354 } else {
381 return ERR_CAST(m); 355 ns = current->nsproxy->ipc_ns;
382 atomic_inc(&m->mnt_sb->s_active); 356 }
383 down_write(&m->mnt_sb->s_umount); 357 return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
384 return dget(m->mnt_root);
385} 358}
386 359
387static void init_once(void *foo) 360static void init_once(void *foo)
@@ -771,16 +744,13 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro,
771static int do_mq_open(const char __user *u_name, int oflag, umode_t mode, 744static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
772 struct mq_attr *attr) 745 struct mq_attr *attr)
773{ 746{
774 struct vfsmount *mnt = mq_internal_mount(); 747 struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
775 struct dentry *root; 748 struct dentry *root = mnt->mnt_root;
776 struct filename *name; 749 struct filename *name;
777 struct path path; 750 struct path path;
778 int fd, error; 751 int fd, error;
779 int ro; 752 int ro;
780 753
781 if (IS_ERR(mnt))
782 return PTR_ERR(mnt);
783
784 audit_mq_open(oflag, mode, attr); 754 audit_mq_open(oflag, mode, attr);
785 755
786 if (IS_ERR(name = getname(u_name))) 756 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,
791 goto out_putname; 761 goto out_putname;
792 762
793 ro = mnt_want_write(mnt); /* we'll drop it in any case */ 763 ro = mnt_want_write(mnt); /* we'll drop it in any case */
794 root = mnt->mnt_root;
795 inode_lock(d_inode(root)); 764 inode_lock(d_inode(root));
796 path.dentry = lookup_one_len(name->name, root, strlen(name->name)); 765 path.dentry = lookup_one_len(name->name, root, strlen(name->name));
797 if (IS_ERR(path.dentry)) { 766 if (IS_ERR(path.dentry)) {
@@ -840,9 +809,6 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
840 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 809 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
841 struct vfsmount *mnt = ipc_ns->mq_mnt; 810 struct vfsmount *mnt = ipc_ns->mq_mnt;
842 811
843 if (!mnt)
844 return -ENOENT;
845
846 name = getname(u_name); 812 name = getname(u_name);
847 if (IS_ERR(name)) 813 if (IS_ERR(name))
848 return PTR_ERR(name); 814 return PTR_ERR(name);
@@ -1569,26 +1535,28 @@ int mq_init_ns(struct ipc_namespace *ns)
1569 ns->mq_msgsize_max = DFLT_MSGSIZEMAX; 1535 ns->mq_msgsize_max = DFLT_MSGSIZEMAX;
1570 ns->mq_msg_default = DFLT_MSG; 1536 ns->mq_msg_default = DFLT_MSG;
1571 ns->mq_msgsize_default = DFLT_MSGSIZE; 1537 ns->mq_msgsize_default = DFLT_MSGSIZE;
1572 ns->mq_mnt = NULL;
1573 1538
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 }
1574 return 0; 1545 return 0;
1575} 1546}
1576 1547
1577void mq_clear_sbinfo(struct ipc_namespace *ns) 1548void mq_clear_sbinfo(struct ipc_namespace *ns)
1578{ 1549{
1579 if (ns->mq_mnt) 1550 ns->mq_mnt->mnt_sb->s_fs_info = NULL;
1580 ns->mq_mnt->mnt_sb->s_fs_info = NULL;
1581} 1551}
1582 1552
1583void mq_put_mnt(struct ipc_namespace *ns) 1553void mq_put_mnt(struct ipc_namespace *ns)
1584{ 1554{
1585 if (ns->mq_mnt) 1555 kern_unmount(ns->mq_mnt);
1586 kern_unmount(ns->mq_mnt);
1587} 1556}
1588 1557
1589static int __init init_mqueue_fs(void) 1558static int __init init_mqueue_fs(void)
1590{ 1559{
1591 struct vfsmount *m;
1592 int error; 1560 int error;
1593 1561
1594 mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache", 1562 mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
@@ -1610,10 +1578,6 @@ static int __init init_mqueue_fs(void)
1610 if (error) 1578 if (error)
1611 goto out_filesystem; 1579 goto out_filesystem;
1612 1580
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;
1617 return 0; 1581 return 0;
1618 1582
1619out_filesystem: 1583out_filesystem: