[PATCH][xenial/unstable] UBUNTU: SAUCE: (namespace) mqueue: Super blocks must be owned by the user ns which owns the ipc ns
Seth Forshee
seth.forshee at canonical.com
Tue May 17 03:05:13 UTC 2016
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: Seth Forshee <seth.forshee at canonical.com>
---
fs/super.c | 16 +++++++++++++---
include/linux/fs.h | 3 +++
ipc/mqueue.c | 7 +++++--
ipc/namespace.c | 4 ++--
4 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/fs/super.c b/fs/super.c
index bacecf1..35e46ba 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -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);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9a2a72fa..04d2149 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -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,
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 161a180..c447e65 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -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)
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 068caf1..adfe6f0 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -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;
}
--
2.7.4
More information about the kernel-team
mailing list