Commit dec77184 authored by Seth Forshee's avatar Seth Forshee Committed by Kamal Mostafa

UBUNTU: SAUCE: (namespace) mqueue: Super blocks must be owned by the user ns which owns the ipc ns

BugLink: http://bugs.launchpad.net/bugs/1582378

s_user_ns for an mqueue super block needs to be set to the user
ns which owns the ipc ns, otherwise it will not be mountable in
that user ns. This is not currently the case for an
unshare(CLONE_NEWIPC|CLONE_NEWUSER) as the internal mount of the
super block for the new ipc ns is done before the new user
namespace is installed.

Since s_user_ns = ipc_ns->user_ns is the only arrangement that
makes sense for mqueue, the initial kernel mount can simply pass
that namespace to sget_userns(). In addition we should do the
same for userspace mounts to preserve the behavior that allows
a user privileged towards ipc_ns->user_ns to mount mqueue from a
different user ns. The existing checks already ensure that the
user has sufficient privileges for the mount.
Signed-off-by: default avatarSeth Forshee <seth.forshee@canonical.com>
Acked-by: default avatarTim Gardner <tim.gardner@canonical.com>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 2a157287
......@@ -951,12 +951,14 @@ static int ns_set_super(struct super_block *sb, void *data)
return set_anon_super(sb, NULL);
}
struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
void *data, int (*fill_super)(struct super_block *, void *, int))
struct dentry *mount_ns_userns(struct file_system_type *fs_type, int flags,
struct user_namespace *user_ns, void *data,
int (*fill_super)(struct super_block *, void *, int))
{
struct super_block *sb;
sb = sget(fs_type, ns_test_super, ns_set_super, flags, data);
sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags, user_ns,
data);
if (IS_ERR(sb))
return ERR_CAST(sb);
......@@ -973,6 +975,14 @@ struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
return dget(sb->s_root);
}
EXPORT_SYMBOL(mount_ns_userns);
struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
void *data, int (*fill_super)(struct super_block *, void *, int))
{
return mount_ns_userns(fs_type, flags, current_user_ns(), data,
fill_super);
}
EXPORT_SYMBOL(mount_ns);
......
......@@ -1976,6 +1976,9 @@ struct file_system_type {
#define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
extern struct dentry *mount_ns_userns(struct file_system_type *fs_type,
int flags, struct user_namespace *userns, void *data,
int (*fill_super)(struct super_block *, void *, int));
extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
void *data, int (*fill_super)(struct super_block *, void *, int));
extern struct dentry *mount_bdev(struct file_system_type *fs_type,
......
......@@ -326,8 +326,10 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
{
struct ipc_namespace *ns = data;
if (!(flags & MS_KERNMOUNT)) {
struct ipc_namespace *ns = current->nsproxy->ipc_ns;
ns = current->nsproxy->ipc_ns;
/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
* over the ipc namespace.
*/
......@@ -336,7 +338,8 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type,
data = ns;
}
return mount_ns(fs_type, flags, data, mqueue_fill_super);
return mount_ns_userns(fs_type, flags, ns->user_ns, data,
mqueue_fill_super);
}
static void init_once(void *foo)
......
......@@ -34,8 +34,10 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
ns->ns.ops = &ipcns_operations;
atomic_set(&ns->count, 1);
ns->user_ns = get_user_ns(user_ns);
err = mq_init_ns(ns);
if (err) {
put_user_ns(ns->user_ns);
ns_free_inum(&ns->ns);
kfree(ns);
return ERR_PTR(err);
......@@ -46,8 +48,6 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
msg_init_ns(ns);
shm_init_ns(ns);
ns->user_ns = get_user_ns(user_ns);
return ns;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment